Skip to content

Commit cdc48b5

Browse files
author
jeffyanta
authored
New memory account structure (#190)
* Update init memory instruction args * Hanlde unmarshalling both version of memory accounts * Reduce duplicated code for unmarshalling memory account structs * Rename simple allocator to slice allocator
1 parent 973241d commit cdc48b5

File tree

6 files changed

+101
-68
lines changed

6 files changed

+101
-68
lines changed

pkg/solana/cvm/accounts_memory_account.go

Lines changed: 63 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,31 @@ const (
1414
)
1515

1616
type MemoryAccount struct {
17-
Vm ed25519.PublicKey
18-
Name string
19-
Bump uint8
20-
Layout MemoryLayout
17+
Vm ed25519.PublicKey
18+
Name string
19+
Bump uint8
20+
Version MemoryVersion
21+
AccountSize uint16
22+
NumAccounts uint32
2123
}
2224

2325
type MemoryAccountWithData struct {
24-
Vm ed25519.PublicKey
25-
Name string
26-
Bump uint8
27-
Layout MemoryLayout
28-
Data SimpleMemoryAllocator // todo: support other implementations
26+
Vm ed25519.PublicKey
27+
Name string
28+
Bump uint8
29+
Version MemoryVersion
30+
AccountSize uint16
31+
NumAccounts uint32
32+
Data SliceAllocator // todo: support other implementations
2933
}
3034

3135
const MemoryAccountSize = (8 + // discriminator
3236
32 + // vm
3337
MaxMemoryAccountNameLength + // name
3438
1 + // bump
35-
6 + // padding
36-
1) // layout
39+
1 + // version
40+
2 + // account_size
41+
4) // num_accounts
3742

3843
var MemoryAccountDiscriminator = []byte{byte(AccountTypeMemory), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
3944

@@ -53,77 +58,81 @@ func (obj *MemoryAccount) Unmarshal(data []byte) error {
5358
getKey(data, &obj.Vm, &offset)
5459
getFixedString(data, &obj.Name, MaxMemoryAccountNameLength, &offset)
5560
getUint8(data, &obj.Bump, &offset)
56-
offset += 6 // padding
57-
getMemoryLayout(data, &obj.Layout, &offset)
61+
getMemoryVersion(data, &obj.Version, &offset)
62+
63+
switch obj.Version {
64+
case MemoryVersionV0:
65+
var layout MemoryLayout
66+
offset += 5 // padding
67+
getMemoryLayout(data, &layout, &offset)
68+
69+
switch layout {
70+
case MemoryLayoutTimelock:
71+
obj.AccountSize = uint16(GetVirtualAccountSizeInMemory(VirtualAccountTypeTimelock))
72+
case MemoryLayoutNonce:
73+
obj.AccountSize = uint16(GetVirtualAccountSizeInMemory(VirtualAccountTypeDurableNonce))
74+
case MemoryLayoutRelay:
75+
obj.AccountSize = uint16(GetVirtualAccountSizeInMemory(VirtualAccountTypeRelay))
76+
default:
77+
return errors.New("unsupported memory layout")
78+
}
79+
obj.NumAccounts = MemoryV0NumAccounts
80+
81+
case MemoryVersionV1:
82+
getUint16(data, &obj.AccountSize, &offset)
83+
getUint32(data, &obj.NumAccounts, &offset)
84+
85+
default:
86+
return errors.New("invalid memory account version")
87+
}
5888

5989
return nil
6090
}
6191

6292
func (obj *MemoryAccount) String() string {
6393
return fmt.Sprintf(
64-
"MemoryAccount{vm=%s,bump=%d,name=%s,layout=%d}",
94+
"MemoryAccount{vm=%s,bump=%d,name=%s,version=%d,num_accounts=%d,account_size=%d}",
6595
base58.Encode(obj.Vm),
6696
obj.Bump,
6797
obj.Name,
68-
obj.Layout,
98+
obj.Version,
99+
obj.NumAccounts,
100+
obj.AccountSize,
69101
)
70102
}
71103

72104
func (obj *MemoryAccountWithData) Unmarshal(data []byte) error {
73-
if len(data) < MemoryAccountSize {
74-
return ErrInvalidAccountData
105+
var memoryAccount MemoryAccount
106+
if err := memoryAccount.Unmarshal(data); err != nil {
107+
return err
75108
}
76109

77-
var offset int
110+
obj.Vm = memoryAccount.Vm
111+
obj.Name = memoryAccount.Name
112+
obj.Bump = memoryAccount.Bump
113+
obj.Version = memoryAccount.Version
114+
obj.AccountSize = memoryAccount.AccountSize
115+
obj.NumAccounts = memoryAccount.NumAccounts
78116

79-
var discriminator []byte
80-
getDiscriminator(data, &discriminator, &offset)
81-
if !bytes.Equal(discriminator, MemoryAccountDiscriminator) {
117+
if len(data) < MemoryAccountSize+GetSliceAllocatorSize(int(obj.NumAccounts), int(obj.AccountSize)) {
82118
return ErrInvalidAccountData
83119
}
84120

85-
getKey(data, &obj.Vm, &offset)
86-
getFixedString(data, &obj.Name, MaxMemoryAccountNameLength, &offset)
87-
getUint8(data, &obj.Bump, &offset)
88-
offset += 6 // padding
89-
getMemoryLayout(data, &obj.Layout, &offset)
90-
91-
switch obj.Layout {
92-
case MemoryLayoutTimelock:
93-
capacity := CompactStateItems
94-
itemSize := int(GetVirtualAccountSizeInMemory(VirtualAccountTypeTimelock))
95-
if len(data) < MemoryAccountSize+GetSimpleMemoryAllocatorSize(capacity, itemSize) {
96-
return ErrInvalidAccountData
97-
}
98-
getSimpleMemoryAllocator(data, &obj.Data, capacity, itemSize, &offset)
99-
case MemoryLayoutNonce:
100-
capacity := CompactStateItems
101-
itemSize := int(GetVirtualAccountSizeInMemory(VirtualAccountTypeDurableNonce))
102-
if len(data) < MemoryAccountSize+GetSimpleMemoryAllocatorSize(capacity, itemSize) {
103-
return ErrInvalidAccountData
104-
}
105-
getSimpleMemoryAllocator(data, &obj.Data, capacity, itemSize, &offset)
106-
case MemoryLayoutRelay:
107-
capacity := CompactStateItems
108-
itemSize := int(GetVirtualAccountSizeInMemory(VirtualAccountTypeRelay))
109-
if len(data) < MemoryAccountSize+GetSimpleMemoryAllocatorSize(capacity, itemSize) {
110-
return ErrInvalidAccountData
111-
}
112-
getSimpleMemoryAllocator(data, &obj.Data, capacity, itemSize, &offset)
113-
default:
114-
return errors.New("unsupported memory layout")
115-
}
121+
offset := MemoryAccountSize
122+
getSliceAllocator(data, &obj.Data, int(obj.NumAccounts), int(obj.AccountSize), &offset)
116123

117124
return nil
118125
}
119126

120127
func (obj *MemoryAccountWithData) String() string {
121128
return fmt.Sprintf(
122-
"MemoryAccountWithData{vm=%s,name=%s,bump=%d,layout=%d,data=%s}",
129+
"MemoryAccountWithData{vm=%s,name=%s,bump=%d,version=%d,num_accounts=%d,account_size=%d,data=%s}",
123130
base58.Encode(obj.Vm),
124131
obj.Name,
125132
obj.Bump,
126-
obj.Layout,
133+
obj.Version,
134+
obj.NumAccounts,
135+
obj.AccountSize,
127136
obj.Data.String(),
128137
)
129138
}

pkg/solana/cvm/instructions_init_memory.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import (
88

99
const (
1010
InitMemoryInstructionArgsSize = (MaxMemoryAccountNameLength + // name
11-
1 + // layout
11+
4 + // num_accounts
12+
2 + // account_size
1213
1) // vm_memory_bump
1314
)
1415

1516
type InitMemoryInstructionArgs struct {
1617
Name string
17-
Layout MemoryLayout
18+
NumAccounts uint32
19+
AccountSize uint16
1820
VmMemoryBump uint8
1921
}
2022

@@ -35,7 +37,8 @@ func NewInitMemoryInstruction(
3537

3638
putCodeInstruction(data, CodeInstructionInitMemory, &offset)
3739
putFixedString(data, args.Name, MaxMemoryAccountNameLength, &offset)
38-
putMemoryLayout(data, args.Layout, &offset)
40+
putUint32(data, args.NumAccounts, &offset)
41+
putUint16(data, args.AccountSize, &offset)
3942
putUint8(data, args.VmMemoryBump, &offset)
4043

4144
return solana.Instruction{

pkg/solana/cvm/types_memory_allocator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package cvm
22

33
const (
4-
CompactStateItems = 32_000
4+
MemoryV0NumAccounts = 32_000
55
)
66

77
type MemoryAllocator interface {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package cvm
2+
3+
type MemoryVersion uint8
4+
5+
const (
6+
MemoryVersionV0 MemoryVersion = iota
7+
MemoryVersionV1
8+
)
9+
10+
func putMemoryVersion(dst []byte, v MemoryVersion, offset *int) {
11+
dst[*offset] = uint8(v)
12+
*offset += 1
13+
}
14+
func getMemoryVersion(src []byte, dst *MemoryVersion, offset *int) {
15+
*dst = MemoryVersion(src[*offset])
16+
*offset += 1
17+
}

pkg/solana/cvm/types_simple_memory_allocator.go renamed to pkg/solana/cvm/types_slice_allocator.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import (
77
"github.com/mr-tron/base58"
88
)
99

10-
type SimpleMemoryAllocator struct {
10+
type SliceAllocator struct {
1111
State ItemStateArray
1212
Data [][]byte
1313
}
1414

15-
func (obj *SimpleMemoryAllocator) Unmarshal(data []byte, capacity, itemSize int) error {
16-
if len(data) < GetSimpleMemoryAllocatorSize(capacity, itemSize) {
15+
func (obj *SliceAllocator) Unmarshal(data []byte, capacity, itemSize int) error {
16+
if len(data) < GetSliceAllocatorSize(capacity, itemSize) {
1717
return ErrInvalidAccountData
1818
}
1919

@@ -30,19 +30,19 @@ func (obj *SimpleMemoryAllocator) Unmarshal(data []byte, capacity, itemSize int)
3030
return nil
3131
}
3232

33-
func getSimpleMemoryAllocator(src []byte, dst *SimpleMemoryAllocator, capacity, itemSize int, offset *int) {
33+
func getSliceAllocator(src []byte, dst *SliceAllocator, capacity, itemSize int, offset *int) {
3434
dst.Unmarshal(src[*offset:], capacity, itemSize)
35-
*offset += GetSimpleMemoryAllocatorSize(capacity, itemSize)
35+
*offset += GetSliceAllocatorSize(capacity, itemSize)
3636
}
3737

38-
func (obj *SimpleMemoryAllocator) IsAllocated(index int) bool {
38+
func (obj *SliceAllocator) IsAllocated(index int) bool {
3939
if index >= len(obj.State) {
4040
return false
4141
}
4242
return obj.State[index] == ItemStateAllocated
4343
}
4444

45-
func (obj *SimpleMemoryAllocator) Read(index int) ([]byte, bool) {
45+
func (obj *SliceAllocator) Read(index int) ([]byte, bool) {
4646
if !obj.IsAllocated(index) {
4747
return nil, false
4848
}
@@ -52,21 +52,21 @@ func (obj *SimpleMemoryAllocator) Read(index int) ([]byte, bool) {
5252
return copied, true
5353
}
5454

55-
func (obj *SimpleMemoryAllocator) String() string {
55+
func (obj *SliceAllocator) String() string {
5656
dataStringValues := make([]string, len(obj.Data))
5757
for i := 0; i < len(obj.Data); i++ {
5858
dataStringValues[i] = base58.Encode(obj.Data[i])
5959
}
6060
dataString := fmt.Sprintf("[%s]", strings.Join(dataStringValues, ","))
6161

6262
return fmt.Sprintf(
63-
"SimpleMemoryAllocator{state=%s,data=%s}",
63+
"SliceAllocator{state=%s,data=%s}",
6464
obj.State.String(),
6565
dataString,
6666
)
6767
}
6868

69-
func GetSimpleMemoryAllocatorSize(capacity, itemSize int) int {
69+
func GetSliceAllocatorSize(capacity, itemSize int) int {
7070
return (capacity*ItemStateSize + // state
7171
capacity*itemSize) // data
7272
}

pkg/solana/cvm/utils.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ func putUint32(dst []byte, v uint32, offset *int) {
107107
binary.LittleEndian.PutUint32(dst[*offset:], v)
108108
*offset += 4
109109
}
110+
func getUint32(src []byte, dst *uint32, offset *int) {
111+
*dst = binary.LittleEndian.Uint32(src[*offset:])
112+
*offset += 4
113+
}
110114

111115
func putUint64(dst []byte, v uint64, offset *int) {
112116
binary.LittleEndian.PutUint64(dst[*offset:], v)

0 commit comments

Comments
 (0)