From e3834ac4eecab36e6f5a1f041ad842f08204ebfc Mon Sep 17 00:00:00 2001 From: lightclient Date: Wed, 21 Aug 2024 15:07:33 -0600 Subject: [PATCH] all: update to new 7702 spec --- core/state/statedb.go | 61 +++++++++++++-------------- core/state_transition.go | 46 +++++++++++--------- core/types/gen_authorization.go | 32 ++++++-------- core/types/transaction_marshalling.go | 5 ++- core/types/tx_setcode.go | 31 +++++++++++--- core/vm/evm.go | 18 ++++---- core/vm/instructions.go | 13 +++--- core/vm/interface.go | 5 ++- tests/gen_stauthorization.go | 16 ++----- tests/state_test_util.go | 4 +- 10 files changed, 122 insertions(+), 109 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index a7fb5b884fa6..0bff9353f38b 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -73,11 +73,6 @@ func (m *mutation) isDelete() bool { return m.typ == deletion } -type delegation struct { - code []byte - codeHash common.Hash -} - // StateDB structs within the ethereum protocol are used to store anything // within the merkle trie. StateDBs take care of caching and storing // nested states. It's the general query interface to retrieve: @@ -146,9 +141,6 @@ type StateDB struct { // Transient storage transientStorage transientStorage - // Transient delegation of accounts to code - transientDelegation map[common.Address]delegation - // Journal of state modifications. This is the backbone of // Snapshot and RevertToSnapshot. journal *journal @@ -327,9 +319,6 @@ func (s *StateDB) SubRefund(gas uint64) { // Exist reports whether the given account address exists in the state. // Notably this also returns true for self-destructed accounts. func (s *StateDB) Exist(addr common.Address) bool { - if _, ok := s.transientDelegation[addr]; ok { - return true - } return s.getStateObject(addr) != nil } @@ -375,9 +364,6 @@ func (s *StateDB) TxIndex() int { } func (s *StateDB) GetCode(addr common.Address) []byte { - if d, ok := s.transientDelegation[addr]; ok { - return d.code - } stateObject := s.getStateObject(addr) if stateObject != nil { return stateObject.Code() @@ -386,9 +372,6 @@ func (s *StateDB) GetCode(addr common.Address) []byte { } func (s *StateDB) GetCodeSize(addr common.Address) int { - if d, ok := s.transientDelegation[addr]; ok { - return len(d.code) - } stateObject := s.getStateObject(addr) if stateObject != nil { return stateObject.CodeSize() @@ -397,9 +380,6 @@ func (s *StateDB) GetCodeSize(addr common.Address) int { } func (s *StateDB) GetCodeHash(addr common.Address) common.Hash { - if d, ok := s.transientDelegation[addr]; ok { - return d.codeHash - } stateObject := s.getStateObject(addr) if stateObject != nil { return common.BytesToHash(stateObject.CodeHash()) @@ -407,6 +387,22 @@ func (s *StateDB) GetCodeHash(addr common.Address) common.Hash { return common.Hash{} } +func (s *StateDB) ResolveCode(addr common.Address) []byte { + stateObject := s.resolveStateObject(addr) + if stateObject != nil { + return stateObject.Code() + } + return nil +} + +func (s *StateDB) ResolveCodeHash(addr common.Address) common.Hash { + stateObject := s.resolveStateObject(addr) + if stateObject != nil { + return common.BytesToHash(stateObject.CodeHash()) + } + return common.Hash{} +} + // GetState retrieves the value associated with the specific key. func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { stateObject := s.getStateObject(addr) @@ -658,6 +654,18 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { return obj } +func (s *StateDB) resolveStateObject(addr common.Address) *stateObject { + obj := s.getStateObject(addr) + if obj == nil { + return nil + } + addr, ok := types.ParseDelegation(obj.Code()) + if !ok { + return obj + } + return s.getStateObject(addr) +} + func (s *StateDB) setStateObject(object *stateObject) { s.stateObjects[object.Address()] = object } @@ -1411,7 +1419,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er // - Reset access list (Berlin) // - Add coinbase to access list (EIP-3651) // - Reset transient storage (EIP-1153) -func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList, authList []types.SetCodeDelegation) { +func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) { if rules.IsEIP2929 && rules.IsEIP4762 { panic("eip2929 and eip4762 are both activated") } @@ -1440,17 +1448,6 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d } // Reset transient storage at the beginning of transaction execution s.transientStorage = newTransientStorage() - - // Set temporary code delegations. - s.transientDelegation = nil - if authList != nil { - td := make(map[common.Address]delegation) - for _, auth := range authList { - td[auth.From] = delegation{s.GetCode(auth.Target), s.GetCodeHash(auth.Target)} - s.accessList.AddAddress(auth.From) - } - s.transientDelegation = td - } } // AddAddressToAccessList adds the given address to the access list diff --git a/core/state_transition.go b/core/state_transition.go index 81298ecffaa5..0d7921ac549a 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -115,7 +115,7 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList types.Autho gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas } if authList != nil { - gas += uint64(len(authList)) * params.TxAuthTupleGas + gas += uint64(len(authList)) * params.CallNewAccountGas } return gas, nil } @@ -434,40 +434,46 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize) } + // Execute the preparatory steps for state transition which includes: + // - prepare accessList(post-berlin) + // - reset transient storage(eip 1153) + st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList) + // Check authorizations list validity. - var delegations []types.SetCodeDelegation if msg.AuthList != nil { seen := make(map[common.Address]bool) for _, auth := range msg.AuthList { + // Verify chain ID is 0 or equal to current chain ID. + if auth.ChainID.Sign() != 0 && st.evm.ChainConfig().ChainID.Cmp(auth.ChainID) != 0 { + continue + } authority, err := auth.Authority() if err != nil { continue } - var nonce *uint64 - if len(auth.Nonce) > 1 { - return nil, fmt.Errorf("authorization must be either empty list or contain exactly one element") + // Check the authority account 1) doesn't have code or has exisiting + // delegation 2) matches the auth's nonce + code := st.state.GetCode(authority) + if _, ok := types.ParseDelegation(code); len(code) != 0 && !ok { + continue } - if len(auth.Nonce) == 1 { - tmp := auth.Nonce[0] - nonce = &tmp + if have := st.state.GetNonce(authority); have != auth.Nonce { + continue } - if nonce != nil { - if have := st.state.GetNonce(authority); have != *nonce { - continue - } + // If the account already exists in state, refund the new account cost + // charged in the initrinsic calculation. + if exists := st.state.Exist(authority); exists { + st.state.AddRefund(params.CallNewAccountGas - params.TxAuthTupleGas) } - if _, ok := seen[authority]; !ok { - seen[authority] = true - delegations = append(delegations, types.SetCodeDelegation{From: authority, Nonce: nonce, Target: auth.Address}) + // Only the first valid occurrence should be used. + if _, ok := seen[authority]; ok { + continue } + seen[authority] = true + st.state.SetCode(authority, types.AddressToDelegation(auth.Address)) } } - // Execute the preparatory steps for state transition which includes: - // - prepare accessList(post-berlin) - // - reset transient storage(eip 1153) - st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList, delegations) - var ( ret []byte vmerr error // vm errors do not effect consensus and are therefore not assigned to err diff --git a/core/types/gen_authorization.go b/core/types/gen_authorization.go index 452977a5f55b..c629a2a4d6fa 100644 --- a/core/types/gen_authorization.go +++ b/core/types/gen_authorization.go @@ -17,21 +17,16 @@ var _ = (*authorizationMarshaling)(nil) func (a Authorization) MarshalJSON() ([]byte, error) { type Authorization struct { ChainID *hexutil.Big - Address common.Address `json:"address" gencodec:"required"` - Nonce []hexutil.Uint64 `json:"nonce" gencodec:"required"` - V *hexutil.Big `json:"v" gencodec:"required"` - R *hexutil.Big `json:"r" gencodec:"required"` - S *hexutil.Big `json:"s" gencodec:"required"` + Address common.Address `json:"address" gencodec:"required"` + Nonce hexutil.Uint64 `json:"nonce" gencodec:"required"` + V *hexutil.Big `json:"v" gencodec:"required"` + R *hexutil.Big `json:"r" gencodec:"required"` + S *hexutil.Big `json:"s" gencodec:"required"` } var enc Authorization enc.ChainID = (*hexutil.Big)(a.ChainID) enc.Address = a.Address - if a.Nonce != nil { - enc.Nonce = make([]hexutil.Uint64, len(a.Nonce)) - for k, v := range a.Nonce { - enc.Nonce[k] = hexutil.Uint64(v) - } - } + enc.Nonce = hexutil.Uint64(a.Nonce) enc.V = (*hexutil.Big)(a.V) enc.R = (*hexutil.Big)(a.R) enc.S = (*hexutil.Big)(a.S) @@ -42,11 +37,11 @@ func (a Authorization) MarshalJSON() ([]byte, error) { func (a *Authorization) UnmarshalJSON(input []byte) error { type Authorization struct { ChainID *hexutil.Big - Address *common.Address `json:"address" gencodec:"required"` - Nonce []hexutil.Uint64 `json:"nonce" gencodec:"required"` - V *hexutil.Big `json:"v" gencodec:"required"` - R *hexutil.Big `json:"r" gencodec:"required"` - S *hexutil.Big `json:"s" gencodec:"required"` + Address *common.Address `json:"address" gencodec:"required"` + Nonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` + V *hexutil.Big `json:"v" gencodec:"required"` + R *hexutil.Big `json:"r" gencodec:"required"` + S *hexutil.Big `json:"s" gencodec:"required"` } var dec Authorization if err := json.Unmarshal(input, &dec); err != nil { @@ -62,10 +57,7 @@ func (a *Authorization) UnmarshalJSON(input []byte) error { if dec.Nonce == nil { return errors.New("missing required field 'nonce' for Authorization") } - a.Nonce = make([]uint64, len(dec.Nonce)) - for k, v := range dec.Nonce { - a.Nonce[k] = uint64(v) - } + a.Nonce = uint64(*dec.Nonce) if dec.V == nil { return errors.New("missing required field 'v' for Authorization") } diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 0aac6d642e5c..7493b72712fc 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -438,9 +438,10 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'nonce' in transaction") } itx.Nonce = uint64(*dec.Nonce) - if dec.To != nil { - itx.To = dec.To + if dec.To == nil { + return errors.New("missing required field 'to' in transaction") } + itx.To = *dec.To if dec.Gas == nil { return errors.New("missing required field 'gas' for txdata") } diff --git a/core/types/tx_setcode.go b/core/types/tx_setcode.go index d7d138062cfd..b36ddf741cb8 100644 --- a/core/types/tx_setcode.go +++ b/core/types/tx_setcode.go @@ -13,6 +13,25 @@ import ( "github.com/holiman/uint256" ) +// DelegationPrefix is used by code to denote the account is delegating to +// another account. +var DelegationPrefix = []byte{0xef, 0x01, 0x00} + +// ParseDelegation tries to parse the address from a delegation slice. +func ParseDelegation(b []byte) (common.Address, bool) { + if len(b) != 23 || !bytes.HasPrefix(b, DelegationPrefix) { + return common.Address{}, false + } + var addr common.Address + copy(addr[:], b[len(DelegationPrefix):]) + return addr, true +} + +// AddressToDelegation adds the delegation prefix to the specified address. +func AddressToDelegation(addr common.Address) []byte { + return append(DelegationPrefix, addr.Bytes()...) +} + // SetCodeTx implements the EIP-7702 transaction type which temporarily installs // the code at the signer's address. type SetCodeTx struct { @@ -21,7 +40,7 @@ type SetCodeTx struct { GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas GasFeeCap *uint256.Int // a.k.a. maxFeePerGas Gas uint64 - To *common.Address `rlp:"nil"` // nil means contract creation + To common.Address Value *uint256.Int Data []byte AccessList AccessList @@ -40,7 +59,7 @@ type SetCodeTx struct { type Authorization struct { ChainID *big.Int Address common.Address `json:"address" gencodec:"required"` - Nonce []uint64 `json:"nonce" gencodec:"required"` + Nonce uint64 `json:"nonce" gencodec:"required"` V *big.Int `json:"v" gencodec:"required"` R *big.Int `json:"r" gencodec:"required"` S *big.Int `json:"s" gencodec:"required"` @@ -49,7 +68,7 @@ type Authorization struct { // field type overrides for gencodec type authorizationMarshaling struct { ChainID *hexutil.Big - Nonce []hexutil.Uint64 + Nonce hexutil.Uint64 V *hexutil.Big R *hexutil.Big S *hexutil.Big @@ -121,7 +140,7 @@ func (a Authorization) Authority() (common.Address, error) { type SetCodeDelegation struct { From common.Address - Nonce *uint64 + Nonce uint64 Target common.Address } @@ -153,7 +172,7 @@ func (a AuthorizationList) WithAddress() []AuthorizationTuple { func (tx *SetCodeTx) copy() TxData { cpy := &SetCodeTx{ Nonce: tx.Nonce, - To: copyAddressPtr(tx.To), + To: tx.To, Data: common.CopyBytes(tx.Data), Gas: tx.Gas, // These are copied below. @@ -204,7 +223,7 @@ func (tx *SetCodeTx) gasTipCap() *big.Int { return tx.GasTipCap.ToBig() } func (tx *SetCodeTx) gasPrice() *big.Int { return tx.GasFeeCap.ToBig() } func (tx *SetCodeTx) value() *big.Int { return tx.Value.ToBig() } func (tx *SetCodeTx) nonce() uint64 { return tx.Nonce } -func (tx *SetCodeTx) to() *common.Address { return tx.To } +func (tx *SetCodeTx) to() *common.Address { tmp := tx.To; return &tmp } func (tx *SetCodeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { if baseFee == nil { diff --git a/core/vm/evm.go b/core/vm/evm.go index 1944189b5da2..1d91da84e10a 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -230,7 +230,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. - code := evm.StateDB.GetCode(addr) + code := evm.StateDB.ResolveCode(addr) if witness := evm.StateDB.Witness(); witness != nil { witness.AddCode(code) } @@ -241,7 +241,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // If the account has no code, we can abort here // The depth-check is already done, and precompiles handled above contract := NewContract(caller, AccountRef(addrCopy), value, gas) - contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code) + contract.SetCallCode(&addrCopy, evm.StateDB.ResolveCodeHash(addrCopy), code) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas } @@ -302,9 +302,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // The contract is a scoped environment for this execution context only. contract := NewContract(caller, AccountRef(caller.Address()), value, gas) if witness := evm.StateDB.Witness(); witness != nil { - witness.AddCode(evm.StateDB.GetCode(addrCopy)) + witness.AddCode(evm.StateDB.ResolveCode(addrCopy)) } - contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy)) + contract.SetCallCode(&addrCopy, evm.StateDB.ResolveCodeHash(addrCopy), evm.StateDB.ResolveCode(addrCopy)) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas } @@ -352,9 +352,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // Initialise a new contract and make initialise the delegate values contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate() if witness := evm.StateDB.Witness(); witness != nil { - witness.AddCode(evm.StateDB.GetCode(addrCopy)) + witness.AddCode(evm.StateDB.ResolveCode(addrCopy)) } - contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy)) + contract.SetCallCode(&addrCopy, evm.StateDB.ResolveCodeHash(addrCopy), evm.StateDB.ResolveCode(addrCopy)) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas } @@ -410,9 +410,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // The contract is a scoped environment for this execution context only. contract := NewContract(caller, AccountRef(addrCopy), new(uint256.Int), gas) if witness := evm.StateDB.Witness(); witness != nil { - witness.AddCode(evm.StateDB.GetCode(addrCopy)) + witness.AddCode(evm.StateDB.ResolveCode(addrCopy)) } - contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy)) + contract.SetCallCode(&addrCopy, evm.StateDB.ResolveCodeHash(addrCopy), evm.StateDB.ResolveCode(addrCopy)) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in Homestead this also counts for code storage gas errors. @@ -476,7 +476,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // - the nonce is non-zero // - the code is non-empty // - the storage is non-empty - contractHash := evm.StateDB.GetCodeHash(address) + contractHash := evm.StateDB.ResolveCodeHash(address) storageRoot := evm.StateDB.GetStorageRoot(address) if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 9ec454464363..3a1d1ed6a40f 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -342,9 +342,9 @@ func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) slot := scope.Stack.peek() address := slot.Bytes20() if witness := interpreter.evm.StateDB.Witness(); witness != nil { - witness.AddCode(interpreter.evm.StateDB.GetCode(address)) + witness.AddCode(interpreter.evm.StateDB.ResolveCode(address)) } - slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20()))) + slot.SetUint64(uint64(len(interpreter.evm.StateDB.ResolveCode(slot.Bytes20())))) return nil, nil } @@ -382,7 +382,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) uint64CodeOffset = math.MaxUint64 } addr := common.Address(a.Bytes20()) - code := interpreter.evm.StateDB.GetCode(addr) + code := interpreter.evm.StateDB.ResolveCode(addr) if witness := interpreter.evm.StateDB.Witness(); witness != nil { witness.AddCode(code) } @@ -394,7 +394,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) // opExtCodeHash returns the code hash of a specified account. // There are several cases when the function is called, while we can relay everything -// to `state.GetCodeHash` function to ensure the correctness. +// to `state.ResolveCodeHash` function to ensure the correctness. // // 1. Caller tries to get the code hash of a normal contract account, state // should return the relative code hash and set it as the result. @@ -408,6 +408,9 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) // 4. Caller tries to get the code hash of a precompiled account, the result should be // zero or emptyCodeHash. // +// 4. Caller tries to get the code hash of a delegated account, the result should be +// equal the result of calling extcodehash on the account directly. +// // It is worth noting that in order to avoid unnecessary create and clean, all precompile // accounts on mainnet have been transferred 1 wei, so the return here should be // emptyCodeHash. If the precompile account is not transferred any amount on a private or @@ -424,7 +427,7 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) if interpreter.evm.StateDB.Empty(address) { slot.Clear() } else { - slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes()) + slot.SetBytes(interpreter.evm.StateDB.ResolveCodeHash(address).Bytes()) } return nil, nil } diff --git a/core/vm/interface.go b/core/vm/interface.go index 766e7aecad77..6079ca7847e4 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -45,6 +45,9 @@ type StateDB interface { SetCode(common.Address, []byte) GetCodeSize(common.Address) int + ResolveCodeHash(common.Address) common.Hash + ResolveCode(common.Address) []byte + AddRefund(uint64) SubRefund(uint64) GetRefund() uint64 @@ -81,7 +84,7 @@ type StateDB interface { // PointCache returns the point cache used in computations PointCache() *utils.PointCache - Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList, authList []types.SetCodeDelegation) + Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) RevertToSnapshot(int) Snapshot() int diff --git a/tests/gen_stauthorization.go b/tests/gen_stauthorization.go index 5f1a99a99da7..6254600b2bb8 100644 --- a/tests/gen_stauthorization.go +++ b/tests/gen_stauthorization.go @@ -18,7 +18,7 @@ func (s stAuthorization) MarshalJSON() ([]byte, error) { type stAuthorization struct { ChainID *math.HexOrDecimal256 Address common.Address `json:"address" gencodec:"required"` - Nonce []math.HexOrDecimal64 `json:"nonce" gencodec:"required"` + Nonce math.HexOrDecimal64 `json:"nonce" gencodec:"required"` V *math.HexOrDecimal256 `json:"v" gencodec:"required"` R *math.HexOrDecimal256 `json:"r" gencodec:"required"` S *math.HexOrDecimal256 `json:"s" gencodec:"required"` @@ -26,12 +26,7 @@ func (s stAuthorization) MarshalJSON() ([]byte, error) { var enc stAuthorization enc.ChainID = (*math.HexOrDecimal256)(s.ChainID) enc.Address = s.Address - if s.Nonce != nil { - enc.Nonce = make([]math.HexOrDecimal64, len(s.Nonce)) - for k, v := range s.Nonce { - enc.Nonce[k] = math.HexOrDecimal64(v) - } - } + enc.Nonce = math.HexOrDecimal64(s.Nonce) enc.V = (*math.HexOrDecimal256)(s.V) enc.R = (*math.HexOrDecimal256)(s.R) enc.S = (*math.HexOrDecimal256)(s.S) @@ -43,7 +38,7 @@ func (s *stAuthorization) UnmarshalJSON(input []byte) error { type stAuthorization struct { ChainID *math.HexOrDecimal256 Address *common.Address `json:"address" gencodec:"required"` - Nonce []math.HexOrDecimal64 `json:"nonce" gencodec:"required"` + Nonce *math.HexOrDecimal64 `json:"nonce" gencodec:"required"` V *math.HexOrDecimal256 `json:"v" gencodec:"required"` R *math.HexOrDecimal256 `json:"r" gencodec:"required"` S *math.HexOrDecimal256 `json:"s" gencodec:"required"` @@ -62,10 +57,7 @@ func (s *stAuthorization) UnmarshalJSON(input []byte) error { if dec.Nonce == nil { return errors.New("missing required field 'nonce' for stAuthorization") } - s.Nonce = make([]uint64, len(dec.Nonce)) - for k, v := range dec.Nonce { - s.Nonce[k] = uint64(v) - } + s.Nonce = uint64(*dec.Nonce) if dec.V == nil { return errors.New("missing required field 'v' for stAuthorization") } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index d14dae1bd81d..9fc59582aea7 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -143,7 +143,7 @@ type stTransactionMarshaling struct { type stAuthorization struct { ChainID *big.Int Address common.Address `json:"address" gencodec:"required"` - Nonce []uint64 `json:"nonce" gencodec:"required"` + Nonce uint64 `json:"nonce" gencodec:"required"` V *big.Int `json:"v" gencodec:"required"` R *big.Int `json:"r" gencodec:"required"` S *big.Int `json:"s" gencodec:"required"` @@ -152,7 +152,7 @@ type stAuthorization struct { // field type overrides for gencodec type stAuthorizationMarshaling struct { ChainID *math.HexOrDecimal256 - Nonce []math.HexOrDecimal64 + Nonce math.HexOrDecimal64 V *math.HexOrDecimal256 R *math.HexOrDecimal256 S *math.HexOrDecimal256