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  }