Skip to content

Commit 6b78362

Browse files
EgeCanerrodrodros
andauthored
feat: state diff migrated compiled class (#3226)
* feat: add migrated class for a bunch of state diffs impl * new field vm state diff: migrated compiled classes * chore: add a bunch of todo and random refactors * update vm2core stateDiff adapter * chore: remove unnecessary dependencies from go.mod & go.sum * feat: update blockifier to rpc v0.16.0-rc.1 (go dependencies) * remove prints in test * Initialize state diff with empty migrated classes --------- Co-authored-by: Rodrigo <rodrodpino@gmail.com>
1 parent fadcf3d commit 6b78362

26 files changed

Lines changed: 330 additions & 162 deletions

adapters/p2p2core/state.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ func AdaptStateDiff(
8787
DeclaredV0Classes: declaredV0Classes,
8888
DeclaredV1Classes: declaredV1Classes,
8989
ReplacedClasses: utils.ToMap(replacedClasses, adaptAddrToClassHash),
90+
MigratedClasses: nil, // todo(rdr): unsure of p2p relationship
9091
}, nil
9192
}
9293

adapters/sn2core/sn2core.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ func AdaptStateUpdate(response *starknet.StateUpdate) (*core.StateUpdate, error)
393393
}, nil
394394
}
395395

396+
// todo(rdr): return `core.StateDiff` by value
396397
func AdaptStateDiff(response *starknet.StateDiff) (*core.StateDiff, error) {
397398
stateDiff := new(core.StateDiff)
398399
stateDiff.DeclaredV0Classes = response.OldDeclaredContracts
@@ -402,6 +403,13 @@ func AdaptStateDiff(response *starknet.StateDiff) (*core.StateDiff, error) {
402403
stateDiff.DeclaredV1Classes[*declaredV1Class.ClassHash] = declaredV1Class.CompiledClassHash
403404
}
404405

406+
stateDiff.MigratedClasses = make(
407+
map[felt.SierraClassHash]felt.CasmClassHash, len(response.MigratedClasses),
408+
)
409+
for _, migratedClass := range response.MigratedClasses {
410+
stateDiff.MigratedClasses[migratedClass.ClassHash] = migratedClass.CompiledClassHash
411+
}
412+
405413
stateDiff.ReplacedClasses = make(map[felt.Felt]*felt.Felt, len(response.ReplacedClasses))
406414
for _, replacedClass := range response.ReplacedClasses {
407415
stateDiff.ReplacedClasses[*replacedClass.Address] = replacedClass.ClassHash

adapters/vm2core/vm2core.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,17 @@ func AdaptOrderedEvent(event vm.OrderedEvent) *core.Event {
1919
}
2020
}
2121

22+
// todo(rdr): this is function definition is twice wrong:
23+
// - the parameters should be received by reference
24+
// - the output param should be return by value
2225
func AdaptOrderedMessageToL1(message vm.OrderedL2toL1Message) *core.L2ToL1Message {
2326
return &core.L2ToL1Message{
2427
From: message.From,
2528
Payload: message.Payload,
26-
To: common.HexToAddress(message.To),
29+
// todo(rdr): this is not correct because it implies the L1 is always Ethereum
30+
// and from Starknet 0.14.1 that is no longer a strong assumption.
31+
// we should have a `felt.L1Address` (or similar)
32+
To: common.HexToAddress(message.To.String()),
2733
}
2834
}
2935

@@ -49,12 +55,18 @@ func AdaptStateDiff(fromStateDiff *vm.StateDiff) core.StateDiff {
4955

5056
// Preallocate all maps with known sizes from fromStateDiff
5157
toStateDiff = core.StateDiff{
52-
StorageDiffs: make(map[felt.Felt]map[felt.Felt]*felt.Felt, len(fromStateDiff.StorageDiffs)),
58+
StorageDiffs: make(
59+
map[felt.Felt]map[felt.Felt]*felt.Felt, len(fromStateDiff.StorageDiffs),
60+
),
5361
Nonces: make(map[felt.Felt]*felt.Felt, len(fromStateDiff.Nonces)),
5462
DeployedContracts: make(map[felt.Felt]*felt.Felt, len(fromStateDiff.DeployedContracts)),
5563
DeclaredV0Classes: make([]*felt.Felt, len(fromStateDiff.DeprecatedDeclaredClasses)),
5664
DeclaredV1Classes: make(map[felt.Felt]*felt.Felt, len(fromStateDiff.DeclaredClasses)),
57-
ReplacedClasses: make(map[felt.Felt]*felt.Felt, len(fromStateDiff.ReplacedClasses)),
65+
MigratedClasses: make(
66+
map[felt.SierraClassHash]felt.CasmClassHash,
67+
len(fromStateDiff.MigratedCompiledClasses),
68+
),
69+
ReplacedClasses: make(map[felt.Felt]*felt.Felt, len(fromStateDiff.ReplacedClasses)),
5870
}
5971

6072
for _, sd := range fromStateDiff.StorageDiffs {
@@ -85,6 +97,11 @@ func AdaptStateDiff(fromStateDiff *vm.StateDiff) core.StateDiff {
8597
ch := rc.ClassHash
8698
toStateDiff.ReplacedClasses[rc.ContractAddress] = &ch
8799
}
100+
101+
for _, mc := range fromStateDiff.MigratedCompiledClasses {
102+
toStateDiff.MigratedClasses[mc.ClassHash] = mc.CompiledClassHash
103+
}
104+
88105
return toStateDiff
89106
}
90107

adapters/vm2core/vm2core_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ func TestAdaptOrderedEvents(t *testing.T) {
4242

4343
func TestAdaptOrderedMessageToL1(t *testing.T) {
4444
require.Equal(t, &core.L2ToL1Message{
45-
From: new(felt.Felt).SetUint64(2),
45+
From: felt.NewFromUint64[felt.Felt](2),
4646
To: common.HexToAddress("0x3"),
4747
Payload: []*felt.Felt{new(felt.Felt).SetUint64(4)},
4848
}, vm2core.AdaptOrderedMessageToL1(vm.OrderedL2toL1Message{
4949
Order: 1,
50-
From: new(felt.Felt).SetUint64(2),
51-
To: "0x3",
50+
From: felt.NewFromUint64[felt.Felt](2),
51+
To: felt.NewFromUint64[felt.Address](0x3),
5252
Payload: []*felt.Felt{new(felt.Felt).SetUint64(4)},
5353
}))
5454
}

blockchain/blockchain.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ func (b *Blockchain) RevertHead() error {
409409
return b.database.Update(b.revertHead)
410410
}
411411

412+
// todo(rdr): return `core.StateDiff` by value
412413
func (b *Blockchain) GetReverseStateDiff() (*core.StateDiff, error) {
413414
var reverseStateDiff *core.StateDiff
414415

core/felt/hash.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ func (h *ClassHash) String() string {
1616
return (*Hash)(h).String()
1717
}
1818

19+
type SierraClassHash ClassHash
20+
21+
func (h *SierraClassHash) String() string {
22+
return (*ClassHash)(h).String()
23+
}
24+
25+
type CasmClassHash ClassHash
26+
27+
func (h *CasmClassHash) String() string {
28+
return (*ClassHash)(h).String()
29+
}
30+
1931
type TransactionHash Hash
2032

2133
func (h *TransactionHash) String() string {

core/state.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -645,11 +645,15 @@ func (s *State) purgesystemContracts() error {
645645
return nil
646646
}
647647

648-
func (s *State) removeDeclaredClasses(blockNumber uint64, v0Classes []*felt.Felt, v1Classes map[felt.Felt]*felt.Felt) error {
649-
totalCapacity := len(v0Classes) + len(v1Classes)
648+
func (s *State) removeDeclaredClasses(
649+
blockNumber uint64,
650+
deprecatedClasses []*felt.Felt,
651+
sierraClasses map[felt.Felt]*felt.Felt,
652+
) error {
653+
totalCapacity := len(deprecatedClasses) + len(sierraClasses)
650654
classHashes := make([]*felt.Felt, 0, totalCapacity)
651-
classHashes = append(classHashes, v0Classes...)
652-
for classHash := range v1Classes {
655+
classHashes = append(classHashes, deprecatedClasses...)
656+
for classHash := range sierraClasses {
653657
classHashes = append(classHashes, classHash.Clone())
654658
}
655659

@@ -705,10 +709,10 @@ func (s *State) purgeContract(addr *felt.Felt) error {
705709
return storageCloser()
706710
}
707711

712+
// todo(rdr): return `StateDiff` by value
708713
func (s *State) GetReverseStateDiff(blockNumber uint64, diff *StateDiff) (*StateDiff, error) {
709714
reversed := *diff
710715

711-
// storage diffs
712716
reversed.StorageDiffs = make(map[felt.Felt]map[felt.Felt]*felt.Felt, len(diff.StorageDiffs))
713717
for addr, storageDiffs := range diff.StorageDiffs {
714718
reversedDiffs := make(map[felt.Felt]*felt.Felt, len(storageDiffs))
@@ -726,7 +730,6 @@ func (s *State) GetReverseStateDiff(blockNumber uint64, diff *StateDiff) (*State
726730
reversed.StorageDiffs[addr] = reversedDiffs
727731
}
728732

729-
// nonces
730733
reversed.Nonces = make(map[felt.Felt]*felt.Felt, len(diff.Nonces))
731734
for addr := range diff.Nonces {
732735
oldNonce := felt.Zero
@@ -740,7 +743,6 @@ func (s *State) GetReverseStateDiff(blockNumber uint64, diff *StateDiff) (*State
740743
reversed.Nonces[addr] = &oldNonce
741744
}
742745

743-
// replaced
744746
reversed.ReplacedClasses = make(map[felt.Felt]*felt.Felt, len(diff.ReplacedClasses))
745747
for addr := range diff.ReplacedClasses {
746748
classHash := felt.Zero

core/state_update.go

Lines changed: 92 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,24 @@ type StateUpdate struct {
1616
}
1717

1818
type StateDiff struct {
19-
StorageDiffs map[felt.Felt]map[felt.Felt]*felt.Felt // addr -> {key -> value, ...}
20-
Nonces map[felt.Felt]*felt.Felt // addr -> nonce
21-
DeployedContracts map[felt.Felt]*felt.Felt // addr -> class hash
22-
DeclaredV0Classes []*felt.Felt // class hashes
23-
DeclaredV1Classes map[felt.Felt]*felt.Felt // class hash -> compiled class hash
24-
ReplacedClasses map[felt.Felt]*felt.Felt // addr -> class hash
19+
// todo(rdr): replace felt.Felt for the right types (felt.Address to felt.What? to felt.What?)
20+
// felt.What? means I'm not sure which type, but if it doesn't exist, create it.
21+
StorageDiffs map[felt.Felt]map[felt.Felt]*felt.Felt // addr -> {key -> value, ...}
22+
// todo(rdr): felt.Address to felt.Nonce (`Nonce` is a new type that should be created?)
23+
Nonces map[felt.Felt]*felt.Felt
24+
// todo(rdr): felt.Addr to felt.ClassHash (do we know if it will be `SierraClassHash or
25+
// `CasmClassHash`)
26+
DeployedContracts map[felt.Felt]*felt.Felt
27+
// todo(rdr): an array of felt.ClassHash, or perhaps, felt.DeprecatedCairoClassHash
28+
// Also, change the name from `DeclaredV0Classes` to `DeprecatedDeclaredClasses`
29+
DeclaredV0Classes []*felt.Felt
30+
// todo(rdr): felt.SierraClassHash to felt.CasmClassHash
31+
DeclaredV1Classes map[felt.Felt]*felt.Felt // class hash -> compiled class hash
32+
// todo(rdr): felt.Address to (felt.SierraClassHash or felt.CasmClassHash, I'm unsure)
33+
ReplacedClasses map[felt.Felt]*felt.Felt // addr -> class hash
34+
// Sierra Class definitions which had their compiled class hash definition (CASM)
35+
// migrated from poseidon hash to blake2s hash (Starknet 0.14.1)
36+
MigratedClasses map[felt.SierraClassHash]felt.CasmClassHash
2537
}
2638

2739
func (d *StateDiff) Length() uint64 {
@@ -35,50 +47,61 @@ func (d *StateDiff) Length() uint64 {
3547
length += len(d.DeclaredV0Classes)
3648
length += len(d.DeclaredV1Classes)
3749
length += len(d.ReplacedClasses)
50+
length += len(d.MigratedClasses)
3851

3952
return uint64(length)
4053
}
4154

4255
func (d *StateDiff) Merge(incoming *StateDiff) {
43-
mergeStorageDiffs := func(oldMap, newMap map[felt.Felt]map[felt.Felt]*felt.Felt) {
44-
for addr, newAddrStorage := range newMap {
45-
if oldAddrStorage, exists := oldMap[addr]; exists {
46-
maps.Copy(oldAddrStorage, newAddrStorage)
47-
} else {
48-
oldMap[addr] = maps.Clone(newAddrStorage)
49-
}
56+
// Merge storage diffs
57+
for addr, newAddrStorage := range incoming.StorageDiffs {
58+
if oldAddrStorage, exists := d.StorageDiffs[addr]; exists {
59+
maps.Copy(oldAddrStorage, newAddrStorage)
60+
} else {
61+
d.StorageDiffs[addr] = maps.Clone(newAddrStorage)
5062
}
5163
}
64+
65+
// Merge everything else
5266
maps.Copy(d.Nonces, incoming.Nonces)
5367
maps.Copy(d.DeployedContracts, incoming.DeployedContracts)
5468
maps.Copy(d.DeclaredV1Classes, incoming.DeclaredV1Classes)
5569
maps.Copy(d.ReplacedClasses, incoming.ReplacedClasses)
56-
mergeStorageDiffs(d.StorageDiffs, incoming.StorageDiffs)
70+
maps.Copy(d.MigratedClasses, incoming.MigratedClasses)
5771
d.DeclaredV0Classes = append(d.DeclaredV0Classes, incoming.DeclaredV0Classes...)
5872
}
5973

60-
var starknetStateDiff0 = new(felt.Felt).SetBytes([]byte("STARKNET_STATE_DIFF0"))
74+
// todo(rdr): Is this global variable justified?
75+
var starknetStateDiff0 = felt.FromBytes[felt.Felt]([]byte("STARKNET_STATE_DIFF0"))
6176

6277
func (d *StateDiff) Hash() *felt.Felt {
6378
digest := new(crypto.PoseidonDigest)
6479

65-
digest.Update(starknetStateDiff0)
80+
digest.Update(&starknetStateDiff0)
6681

6782
// updated_contracts = deployedContracts + replacedClasses
6883
// Digest: [number_of_updated_contracts, address_0, class_hash_0, address_1, class_hash_1, ...].
6984
updatedContractsDigest(d.DeployedContracts, d.ReplacedClasses, digest)
7085

7186
// declared classes
72-
// Digest: [number_of_declared_classes, class_hash_0, compiled_class_hash_0, class_hash_1, compiled_class_hash_1,
73-
// ...].
74-
declaredClassesDigest(d.DeclaredV1Classes, digest)
87+
// Digest: [
88+
// number_of_declared_classes,
89+
// class_hash_0, compiled_class_hash_0,
90+
// class_hash_1, compiled_class_hash_1,
91+
// ...
92+
// ] + [
93+
// migrated_class_hash_0, migrated_compiled_class_hash_0,
94+
// migrated_class_hash_1, migrated_compiled_class_hash_1,
95+
// ...
96+
// ]
97+
declaredClassesDigest(d.DeclaredV1Classes, d.MigratedClasses, digest)
7598

7699
// deprecated_declared_classes
77100
// Digest: [number_of_old_declared_classes, class_hash_0, class_hash_1, ...].
78101
deprecatedDeclaredClassesDigest(d.DeclaredV0Classes, digest)
79102

80103
// Placeholder values
81-
digest.Update(new(felt.Felt).SetUint64(1), new(felt.Felt).SetUint64(0))
104+
digest.Update(&felt.One, &felt.Zero)
82105

83106
// storage_diffs
84107
// Digest: [
@@ -89,12 +112,23 @@ func (d *StateDiff) Hash() *felt.Felt {
89112
storageDiffDigest(d.StorageDiffs, digest)
90113

91114
// nonces
92-
// Digest: [number_of_updated_contracts nonces, contract_address_0, nonce_0, contract_address_1, nonce_1, ...]
115+
// Digest: [
116+
// number_of_updated_contracts nonces,
117+
// contract_address_0, nonce_0,
118+
// contract_address_1, nonce_1,
119+
// ...,
120+
// ]
93121
noncesDigest(d.Nonces, digest)
94122

95123
/*Poseidon(
96-
"STARKNET_STATE_DIFF0", deployed_contracts_and_replaced_classes, declared_classes, deprecated_declared_classes,
97-
1, 0, storage_diffs, nonces
124+
"STARKNET_STATE_DIFF0",
125+
deployed_contracts_and_replaced_classes,
126+
declared_classes,
127+
deprecated_declared_classes,
128+
1,
129+
0,
130+
storage_diffs,
131+
nonces
98132
)*/
99133
return digest.Finish()
100134
}
@@ -114,8 +148,9 @@ func (d *StateDiff) Commitment() *felt.Felt {
114148
hash_of_declared_classes = hash([number_of_declared_classes, class_hash_1, compiled_class_hash_1,
115149
class_hash_2, compiled_class_hash_2, ...])
116150
*/
151+
// todo(rdr): check if commitment is like this too
117152
hashOfDeclaredClasses := new(crypto.PoseidonDigest)
118-
declaredClassesDigest(d.DeclaredV1Classes, hashOfDeclaredClasses)
153+
declaredClassesDigest(d.DeclaredV1Classes, d.MigratedClasses, hashOfDeclaredClasses)
119154

120155
/*
121156
hash_of_old_declared_classes = hash([number_of_old_declared_classes, class_hash_1, class_hash_2, ...])
@@ -173,13 +208,36 @@ func updatedContractsDigest(deployedContracts, replacedClasses map[felt.Felt]*fe
173208
}
174209
}
175210

176-
func declaredClassesDigest(declaredV1Classes map[felt.Felt]*felt.Felt, digest *crypto.PoseidonDigest) {
177-
numOfDeclaredClasses := uint64(len(declaredV1Classes))
178-
digest.Update(new(felt.Felt).SetUint64(numOfDeclaredClasses))
211+
func declaredClassesDigest(
212+
declaredClasses map[felt.Felt]*felt.Felt,
213+
migratedClasses map[felt.SierraClassHash]felt.CasmClassHash,
214+
digest *crypto.PoseidonDigest,
215+
) {
216+
mapsLen := len(declaredClasses) + len(migratedClasses)
217+
numOfDeclaredClasses := felt.FromUint64[felt.Felt](uint64(mapsLen))
218+
digest.Update(&numOfDeclaredClasses)
219+
220+
// Sorting the two keys without actually modifying `declaredClasses` or `migratedClasses`
221+
// to avoid the memory overhead of creating a new map since we **mustn't** mutate them
222+
keys := make([]felt.Felt, mapsLen)
223+
index := 0
224+
for key := range declaredClasses {
225+
keys[index] = key
226+
index += 1
227+
}
228+
for key := range migratedClasses {
229+
// todo(rdr): we shouldn't need to convert the key to a felt here but the right fix
230+
// includes a bigger refactor
231+
keys[index] = felt.Felt(key)
232+
index += 1
233+
}
234+
slices.SortFunc(keys, func(a felt.Felt, b felt.Felt) int { return a.Cmp(&b) })
179235

180-
sortedDeclaredV1ClassHashes := sortedFeltKeys(declaredV1Classes)
236+
// todo(rdr): Is it more performant to do multiple calls to `diget.Update`, or
237+
// pre-store all the values and make a single call to `digest.Update`?
238+
sortedDeclaredV1ClassHashes := sortedFeltKeys(declaredClasses)
181239
for _, classHash := range sortedDeclaredV1ClassHashes {
182-
digest.Update(&classHash, declaredV1Classes[classHash])
240+
digest.Update(&classHash, declaredClasses[classHash])
183241
}
184242
}
185243

@@ -191,7 +249,10 @@ func deprecatedDeclaredClassesDigest(declaredV0Classes []*felt.Felt, digest *cry
191249
digest.Update(declaredV0Classes...)
192250
}
193251

194-
func storageDiffDigest(storageDiffs map[felt.Felt]map[felt.Felt]*felt.Felt, digest *crypto.PoseidonDigest) {
252+
func storageDiffDigest(
253+
storageDiffs map[felt.Felt]map[felt.Felt]*felt.Felt,
254+
digest *crypto.PoseidonDigest,
255+
) {
195256
numOfStorageDiffs := uint64(len(storageDiffs))
196257
digest.Update(new(felt.Felt).SetUint64(numOfStorageDiffs))
197258

@@ -226,5 +287,6 @@ func EmptyStateDiff() StateDiff {
226287
DeclaredV0Classes: []*felt.Felt{},
227288
DeclaredV1Classes: make(map[felt.Felt]*felt.Felt),
228289
ReplacedClasses: make(map[felt.Felt]*felt.Felt),
290+
MigratedClasses: make(map[felt.SierraClassHash]felt.CasmClassHash),
229291
}
230292
}

core/transaction.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ type Event struct {
8585
}
8686

8787
type L1ToL2Message struct {
88+
// todo(rdr): Starknet from 0.14.1 has dropped the assumption that we use an EthAddress
89+
// here. We should change this to felt.Address
8890
From common.Address
8991
Nonce *felt.Felt
9092
Payload []*felt.Felt
@@ -95,7 +97,9 @@ type L1ToL2Message struct {
9597
type L2ToL1Message struct {
9698
From *felt.Felt
9799
Payload []*felt.Felt
98-
To common.Address
100+
// todo(rdr): Starknet from 0.14.1 has dropped the assumption that we use an EthAddress
101+
// here. We should change this to felt.Address
102+
To common.Address
99103
}
100104

101105
type ExecutionResources struct {

0 commit comments

Comments
 (0)