github.com/tacshi/go-ethereum@v0.0.0-20230616113857-84a434e20921/arbitrum_types/txoptions.go (about) 1 package arbitrum_types 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "strings" 7 8 "github.com/pkg/errors" 9 "github.com/tacshi/go-ethereum/common" 10 "github.com/tacshi/go-ethereum/common/hexutil" 11 "github.com/tacshi/go-ethereum/core/state" 12 "github.com/tacshi/go-ethereum/rpc" 13 ) 14 15 type rejectedError struct { 16 msg string 17 } 18 19 func NewRejectedError(msg string) *rejectedError { 20 return &rejectedError{msg: msg} 21 } 22 func (e rejectedError) Error() string { return e.msg } 23 func (rejectedError) ErrorCode() int { return -32003 } 24 25 type limitExceededError struct { 26 msg string 27 } 28 29 func NewLimitExceededError(msg string) *limitExceededError { 30 return &limitExceededError{msg: msg} 31 } 32 func (e limitExceededError) Error() string { return e.msg } 33 func (limitExceededError) ErrorCode() int { return -32005 } 34 35 func WrapOptionsCheckError(err error, msg string) error { 36 wrappedMsg := func(e rpc.Error, msg string) string { 37 return strings.Join([]string{msg, e.Error()}, ":") 38 } 39 switch e := err.(type) { 40 case *rejectedError: 41 return NewRejectedError(wrappedMsg(e, msg)) 42 case *limitExceededError: 43 return NewLimitExceededError(wrappedMsg(e, msg)) 44 default: 45 return errors.Wrap(err, msg) 46 } 47 } 48 49 type RootHashOrSlots struct { 50 RootHash *common.Hash 51 SlotValue map[common.Hash]common.Hash 52 } 53 54 func (r *RootHashOrSlots) UnmarshalJSON(data []byte) error { 55 var hash common.Hash 56 var err error 57 if err = json.Unmarshal(data, &hash); err == nil { 58 r.RootHash = &hash 59 return nil 60 } 61 return json.Unmarshal(data, &r.SlotValue) 62 } 63 64 func (r RootHashOrSlots) MarshalJSON() ([]byte, error) { 65 if r.RootHash != nil { 66 return json.Marshal(*r.RootHash) 67 } 68 return json.Marshal(r.SlotValue) 69 } 70 71 type ConditionalOptions struct { 72 KnownAccounts map[common.Address]RootHashOrSlots `json:"knownAccounts"` 73 BlockNumberMin *hexutil.Uint64 `json:"blockNumberMin,omitempty"` 74 BlockNumberMax *hexutil.Uint64 `json:"blockNumberMax,omitempty"` 75 TimestampMin *hexutil.Uint64 `json:"timestampMin,omitempty"` 76 TimestampMax *hexutil.Uint64 `json:"timestampMax,omitempty"` 77 } 78 79 func (o *ConditionalOptions) Check(l1BlockNumber uint64, l2Timestamp uint64, statedb *state.StateDB) error { 80 if o.BlockNumberMin != nil && l1BlockNumber < uint64(*o.BlockNumberMin) { 81 return NewRejectedError("BlockNumberMin condition not met") 82 } 83 if o.BlockNumberMax != nil && l1BlockNumber > uint64(*o.BlockNumberMax) { 84 return NewRejectedError("BlockNumberMax condition not met") 85 } 86 if o.TimestampMin != nil && l2Timestamp < uint64(*o.TimestampMin) { 87 return NewRejectedError("TimestampMin condition not met") 88 } 89 if o.TimestampMax != nil && l2Timestamp > uint64(*o.TimestampMax) { 90 return NewRejectedError("TimestampMax condition not met") 91 } 92 for address, rootHashOrSlots := range o.KnownAccounts { 93 if rootHashOrSlots.RootHash != nil { 94 trie, err := statedb.StorageTrie(address) 95 if err != nil { 96 return err 97 } 98 if trie == nil { 99 return NewRejectedError("Storage trie not found for address key in knownAccounts option") 100 } 101 if trie.Hash() != *rootHashOrSlots.RootHash { 102 return NewRejectedError("Storage root hash condition not met") 103 } 104 } else if len(rootHashOrSlots.SlotValue) > 0 { 105 for slot, value := range rootHashOrSlots.SlotValue { 106 stored := statedb.GetState(address, slot) 107 if !bytes.Equal(stored.Bytes(), value.Bytes()) { 108 return NewRejectedError("Storage slot value condition not met") 109 } 110 } 111 } // else rootHashOrSlots.SlotValue is empty - ignore it and check the rest of conditions 112 } 113 return nil 114 }