github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/trie/zkproof/orderer.go (about) 1 package zkproof 2 3 import ( 4 "math/big" 5 "sort" 6 7 "github.com/scroll-tech/go-ethereum/common" 8 "github.com/scroll-tech/go-ethereum/common/hexutil" 9 "github.com/scroll-tech/go-ethereum/core/types" 10 ) 11 12 type opIterator interface { 13 next() *types.AccountWrapper 14 } 15 16 type opOrderer interface { 17 readonly(bool) 18 absorb(*types.AccountWrapper) 19 absorbStorage(*types.AccountWrapper, *types.StorageWrapper) 20 end_absorb() opIterator 21 } 22 23 type iterateOp []*types.AccountWrapper 24 25 func (ops *iterateOp) next() *types.AccountWrapper { 26 27 sl := *ops 28 29 if len(sl) == 0 { 30 return nil 31 } 32 33 *ops = sl[1:] 34 return sl[0] 35 } 36 37 type simpleOrderer struct { 38 readOnly int 39 savedOp []*types.AccountWrapper 40 } 41 42 func (od *simpleOrderer) SavedOp() []*types.AccountWrapper { return od.savedOp } 43 44 func (od *simpleOrderer) readonly(mode bool) { 45 if mode { 46 od.readOnly += 1 47 } else if od.readOnly == 0 { 48 panic("unexpected readonly mode stack pop") 49 } else { 50 od.readOnly -= 1 51 } 52 } 53 54 func (od *simpleOrderer) absorb(st *types.AccountWrapper) { 55 if od.readOnly > 0 { 56 return 57 } 58 od.savedOp = append(od.savedOp, st) 59 } 60 61 func (od *simpleOrderer) absorbStorage(st *types.AccountWrapper, _ *types.StorageWrapper) { 62 od.absorb(st) 63 } 64 65 func (od *simpleOrderer) end_absorb() opIterator { 66 ret := iterateOp(od.savedOp) 67 return &ret 68 } 69 70 type multiOpIterator []opIterator 71 72 func (opss *multiOpIterator) next() *types.AccountWrapper { 73 74 sl := *opss 75 if len(sl) == 0 { 76 return nil 77 } 78 79 op := sl[0].next() 80 81 for op == nil { 82 83 sl = sl[1:] 84 *opss = sl 85 if len(sl) == 0 { 86 return nil 87 } 88 op = sl[0].next() 89 } 90 return op 91 } 92 93 type rwTblOrderer struct { 94 readOnly int 95 readOnlySnapshot struct { 96 accounts map[string]*types.AccountWrapper 97 storages map[string]map[string]*types.StorageWrapper 98 } 99 initedData map[common.Address]*types.AccountWrapper 100 101 // help to track all accounts being touched, and provide the 102 // completed account status for storage updating 103 traced map[string]*types.AccountWrapper 104 105 opAccNonce map[string]*types.AccountWrapper 106 opAccBalance map[string]*types.AccountWrapper 107 opAccCodeHash map[string]*types.AccountWrapper 108 opStorage map[string]map[string]*types.StorageWrapper 109 } 110 111 func NewSimpleOrderer() *simpleOrderer { return &simpleOrderer{} } 112 113 func NewRWTblOrderer(inited map[common.Address]*types.StateAccount) *rwTblOrderer { 114 115 initedAcc := make(map[common.Address]*types.AccountWrapper) 116 for addr, data := range inited { 117 if data == nil { 118 initedAcc[addr] = &types.AccountWrapper{ 119 Address: addr, 120 Balance: (*hexutil.Big)(big.NewInt(0)), 121 } 122 } else { 123 bl := data.Balance 124 if bl == nil { 125 bl = big.NewInt(0) 126 } 127 128 initedAcc[addr] = &types.AccountWrapper{ 129 Address: addr, 130 Nonce: data.Nonce, 131 Balance: (*hexutil.Big)(bl), 132 KeccakCodeHash: common.BytesToHash(data.KeccakCodeHash), 133 PoseidonCodeHash: common.BytesToHash(data.PoseidonCodeHash), 134 CodeSize: data.CodeSize, 135 } 136 } 137 138 } 139 140 return &rwTblOrderer{ 141 initedData: initedAcc, 142 traced: make(map[string]*types.AccountWrapper), 143 opAccNonce: make(map[string]*types.AccountWrapper), 144 opAccBalance: make(map[string]*types.AccountWrapper), 145 opAccCodeHash: make(map[string]*types.AccountWrapper), 146 opStorage: make(map[string]map[string]*types.StorageWrapper), 147 } 148 } 149 150 func (od *rwTblOrderer) readonly(mode bool) { 151 if mode { 152 if od.readOnly == 0 { 153 od.readOnlySnapshot.accounts = make(map[string]*types.AccountWrapper) 154 od.readOnlySnapshot.storages = make(map[string]map[string]*types.StorageWrapper) 155 } 156 od.readOnly += 1 157 } else if od.readOnly == 0 { 158 panic("unexpected readonly mode stack pop") 159 } else { 160 od.readOnly -= 1 161 if od.readOnly == 0 { 162 for addrS, st := range od.readOnlySnapshot.accounts { 163 od.absorb(st) 164 if m, existed := od.readOnlySnapshot.storages[addrS]; existed { 165 for _, stg := range m { 166 st.Storage = stg 167 od.absorbStorage(st, nil) 168 } 169 } 170 } 171 } 172 } 173 } 174 175 func (od *rwTblOrderer) absorbStorage(st *types.AccountWrapper, before *types.StorageWrapper) { 176 if st.Storage == nil { 177 panic("do not call absorbStorage ") 178 } 179 180 od.absorb(st) 181 addrStr := st.Address.String() 182 183 if stg := st.Storage; stg != nil { 184 m, existed := od.opStorage[addrStr] 185 if !existed { 186 m = make(map[string]*types.StorageWrapper) 187 od.opStorage[addrStr] = m 188 } 189 190 // key must be unified into 32 bytes 191 keyBytes := hexutil.MustDecode(stg.Key) 192 keyStr := common.BytesToHash(keyBytes).String() 193 194 // trace every "touched" status for readOnly 195 if od.readOnly > 0 { 196 m, existed := od.readOnlySnapshot.storages[addrStr] 197 if !existed { 198 m = make(map[string]*types.StorageWrapper) 199 od.readOnlySnapshot.storages[addrStr] = m 200 } 201 if _, hashTraced := m[keyStr]; !hashTraced { 202 if before != nil { 203 m[keyStr] = before 204 } else { 205 m[keyStr] = stg 206 } 207 208 } 209 } 210 211 m[keyStr] = stg 212 } 213 214 } 215 216 func (od *rwTblOrderer) absorb(st *types.AccountWrapper) { 217 218 initedRef, existed := od.initedData[st.Address] 219 if !existed { 220 panic("encounter unprepared status") 221 } 222 223 addrStr := st.Address.String() 224 225 // trace every "touched" status for readOnly 226 if od.readOnly > 0 { 227 snapShot, existed := od.traced[addrStr] 228 if !existed { 229 snapShot = initedRef 230 } 231 232 if _, hasTraced := od.readOnlySnapshot.accounts[addrStr]; !hasTraced { 233 od.readOnlySnapshot.accounts[addrStr] = copyAccountState(snapShot) 234 } 235 } 236 237 if isDeletedAccount(st) { 238 // for account delete, made a safer data for status 239 st = &types.AccountWrapper{ 240 Address: st.Address, 241 Balance: (*hexutil.Big)(big.NewInt(0)), 242 } 243 } 244 245 od.traced[addrStr] = st 246 247 // notice there would be at least one entry for all 3 fields when accessing an address 248 // this may caused extract "read" op in mpt circuit which has no corresponding one in rwtable 249 // we can avoid it unless obtaining more tips from the understanding of opcode 250 // but it would be ok if we have adopted the new lookup way (root_prev, root_cur) under discussion: 251 // https://github.com/privacy-scaling-explorations/zkevm-specs/issues/217 252 253 if traced, existed := od.opAccNonce[addrStr]; !existed { 254 traced = copyAccountState(st) 255 traced.Balance = initedRef.Balance 256 traced.KeccakCodeHash = initedRef.KeccakCodeHash 257 traced.PoseidonCodeHash = initedRef.PoseidonCodeHash 258 traced.CodeSize = initedRef.CodeSize 259 traced.Storage = nil 260 od.opAccNonce[addrStr] = traced 261 } else { 262 traced.Nonce = st.Nonce 263 } 264 265 if traced, existed := od.opAccBalance[addrStr]; !existed { 266 traced = copyAccountState(st) 267 traced.KeccakCodeHash = initedRef.KeccakCodeHash 268 traced.PoseidonCodeHash = initedRef.PoseidonCodeHash 269 traced.CodeSize = initedRef.CodeSize 270 traced.Storage = nil 271 od.opAccBalance[addrStr] = traced 272 } else { 273 traced.Nonce = st.Nonce 274 traced.Balance = st.Balance 275 } 276 277 if traced, existed := od.opAccCodeHash[addrStr]; !existed { 278 traced = copyAccountState(st) 279 traced.Storage = nil 280 od.opAccCodeHash[addrStr] = traced 281 } else { 282 traced.Nonce = st.Nonce 283 traced.Balance = st.Balance 284 traced.KeccakCodeHash = st.KeccakCodeHash 285 traced.PoseidonCodeHash = st.PoseidonCodeHash 286 traced.CodeSize = st.CodeSize 287 } 288 289 } 290 291 func (od *rwTblOrderer) end_absorb() opIterator { 292 // now sort every map by address / key 293 // inited has collected all address, just sort address once 294 sortedAddrs := make([]string, 0, len(od.traced)) 295 for addrs := range od.traced { 296 sortedAddrs = append(sortedAddrs, addrs) 297 } 298 sort.Strings(sortedAddrs) 299 300 var iterNonce []*types.AccountWrapper 301 var iterBalance []*types.AccountWrapper 302 var iterCodeHash []*types.AccountWrapper 303 var iterStorage []*types.AccountWrapper 304 305 for _, addrStr := range sortedAddrs { 306 307 if v, existed := od.opAccNonce[addrStr]; existed { 308 iterNonce = append(iterNonce, v) 309 } 310 311 if v, existed := od.opAccBalance[addrStr]; existed { 312 iterBalance = append(iterBalance, v) 313 } 314 315 if v, existed := od.opAccCodeHash[addrStr]; existed { 316 iterCodeHash = append(iterCodeHash, v) 317 } 318 319 if stgM, existed := od.opStorage[addrStr]; existed { 320 321 tracedStatus := od.traced[addrStr] 322 if tracedStatus == nil { 323 panic("missed traced status found in storage slot") 324 } 325 326 sortedKeys := make([]string, 0, len(stgM)) 327 for key := range stgM { 328 sortedKeys = append(sortedKeys, key) 329 } 330 sort.Strings(sortedKeys) 331 332 for _, key := range sortedKeys { 333 st := copyAccountState(tracedStatus) 334 st.Storage = stgM[key] 335 iterStorage = append(iterStorage, st) 336 } 337 } 338 339 } 340 341 var finalRet []opIterator 342 for _, arr := range [][]*types.AccountWrapper{iterNonce, iterBalance, iterCodeHash, iterStorage} { 343 wrappedIter := iterateOp(arr) 344 finalRet = append(finalRet, &wrappedIter) 345 } 346 347 wrappedRet := multiOpIterator(finalRet) 348 return &wrappedRet 349 }