mirror of https://github.com/ethereum/go-ethereum
Merge pull request #30456 from ethereum/master
Merge branch 'master' into release/1.14release/1.14 v1.14.9
commit
c350d3acd5
@ -1,113 +0,0 @@ |
||||
// Copyright 2021 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core |
||||
|
||||
import ( |
||||
crand "crypto/rand" |
||||
"errors" |
||||
"math/big" |
||||
mrand "math/rand" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/common/math" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/log" |
||||
"github.com/ethereum/go-ethereum/params" |
||||
) |
||||
|
||||
// ChainReader defines a small collection of methods needed to access the local
|
||||
// blockchain during header verification. It's implemented by both blockchain
|
||||
// and lightchain.
|
||||
type ChainReader interface { |
||||
// Config retrieves the header chain's chain configuration.
|
||||
Config() *params.ChainConfig |
||||
|
||||
// GetTd returns the total difficulty of a local block.
|
||||
GetTd(common.Hash, uint64) *big.Int |
||||
} |
||||
|
||||
// ForkChoice is the fork chooser based on the highest total difficulty of the
|
||||
// chain(the fork choice used in the eth1) and the external fork choice (the fork
|
||||
// choice used in the eth2). This main goal of this ForkChoice is not only for
|
||||
// offering fork choice during the eth1/2 merge phase, but also keep the compatibility
|
||||
// for all other proof-of-work networks.
|
||||
type ForkChoice struct { |
||||
chain ChainReader |
||||
rand *mrand.Rand |
||||
|
||||
// preserve is a helper function used in td fork choice.
|
||||
// Miners will prefer to choose the local mined block if the
|
||||
// local td is equal to the extern one. It can be nil for light
|
||||
// client
|
||||
preserve func(header *types.Header) bool |
||||
} |
||||
|
||||
func NewForkChoice(chainReader ChainReader, preserve func(header *types.Header) bool) *ForkChoice { |
||||
// Seed a fast but crypto originating random generator
|
||||
seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) |
||||
if err != nil { |
||||
log.Crit("Failed to initialize random seed", "err", err) |
||||
} |
||||
return &ForkChoice{ |
||||
chain: chainReader, |
||||
rand: mrand.New(mrand.NewSource(seed.Int64())), |
||||
preserve: preserve, |
||||
} |
||||
} |
||||
|
||||
// ReorgNeeded returns whether the reorg should be applied
|
||||
// based on the given external header and local canonical chain.
|
||||
// In the td mode, the new head is chosen if the corresponding
|
||||
// total difficulty is higher. In the extern mode, the trusted
|
||||
// header is always selected as the head.
|
||||
func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (bool, error) { |
||||
var ( |
||||
localTD = f.chain.GetTd(current.Hash(), current.Number.Uint64()) |
||||
externTd = f.chain.GetTd(extern.Hash(), extern.Number.Uint64()) |
||||
) |
||||
if localTD == nil || externTd == nil { |
||||
return false, errors.New("missing td") |
||||
} |
||||
// Accept the new header as the chain head if the transition
|
||||
// is already triggered. We assume all the headers after the
|
||||
// transition come from the trusted consensus layer.
|
||||
if ttd := f.chain.Config().TerminalTotalDifficulty; ttd != nil && ttd.Cmp(externTd) <= 0 { |
||||
return true, nil |
||||
} |
||||
|
||||
// If the total difficulty is higher than our known, add it to the canonical chain
|
||||
if diff := externTd.Cmp(localTD); diff > 0 { |
||||
return true, nil |
||||
} else if diff < 0 { |
||||
return false, nil |
||||
} |
||||
// Local and external difficulty is identical.
|
||||
// Second clause in the if statement reduces the vulnerability to selfish mining.
|
||||
// Please refer to http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf
|
||||
reorg := false |
||||
externNum, localNum := extern.Number.Uint64(), current.Number.Uint64() |
||||
if externNum < localNum { |
||||
reorg = true |
||||
} else if externNum == localNum { |
||||
var currentPreserve, externPreserve bool |
||||
if f.preserve != nil { |
||||
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern) |
||||
} |
||||
reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5) |
||||
} |
||||
return reorg, nil |
||||
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,313 @@ |
||||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package state |
||||
|
||||
import ( |
||||
"errors" |
||||
"maps" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/core/state/snapshot" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
"github.com/ethereum/go-ethereum/rlp" |
||||
"github.com/ethereum/go-ethereum/trie" |
||||
"github.com/ethereum/go-ethereum/trie/utils" |
||||
"github.com/ethereum/go-ethereum/triedb" |
||||
) |
||||
|
||||
// Reader defines the interface for accessing accounts and storage slots
|
||||
// associated with a specific state.
|
||||
type Reader interface { |
||||
// Account retrieves the account associated with a particular address.
|
||||
//
|
||||
// - Returns a nil account if it does not exist
|
||||
// - Returns an error only if an unexpected issue occurs
|
||||
// - The returned account is safe to modify after the call
|
||||
Account(addr common.Address) (*types.StateAccount, error) |
||||
|
||||
// Storage retrieves the storage slot associated with a particular account
|
||||
// address and slot key.
|
||||
//
|
||||
// - Returns an empty slot if it does not exist
|
||||
// - Returns an error only if an unexpected issue occurs
|
||||
// - The returned storage slot is safe to modify after the call
|
||||
Storage(addr common.Address, slot common.Hash) (common.Hash, error) |
||||
|
||||
// Copy returns a deep-copied state reader.
|
||||
Copy() Reader |
||||
} |
||||
|
||||
// stateReader is a wrapper over the state snapshot and implements the Reader
|
||||
// interface. It provides an efficient way to access flat state.
|
||||
type stateReader struct { |
||||
snap snapshot.Snapshot |
||||
buff crypto.KeccakState |
||||
} |
||||
|
||||
// newStateReader constructs a flat state reader with on the specified state root.
|
||||
func newStateReader(root common.Hash, snaps *snapshot.Tree) (*stateReader, error) { |
||||
snap := snaps.Snapshot(root) |
||||
if snap == nil { |
||||
return nil, errors.New("snapshot is not available") |
||||
} |
||||
return &stateReader{ |
||||
snap: snap, |
||||
buff: crypto.NewKeccakState(), |
||||
}, nil |
||||
} |
||||
|
||||
// Account implements Reader, retrieving the account specified by the address.
|
||||
//
|
||||
// An error will be returned if the associated snapshot is already stale or
|
||||
// the requested account is not yet covered by the snapshot.
|
||||
//
|
||||
// The returned account might be nil if it's not existent.
|
||||
func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error) { |
||||
ret, err := r.snap.Account(crypto.HashData(r.buff, addr.Bytes())) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if ret == nil { |
||||
return nil, nil |
||||
} |
||||
acct := &types.StateAccount{ |
||||
Nonce: ret.Nonce, |
||||
Balance: ret.Balance, |
||||
CodeHash: ret.CodeHash, |
||||
Root: common.BytesToHash(ret.Root), |
||||
} |
||||
if len(acct.CodeHash) == 0 { |
||||
acct.CodeHash = types.EmptyCodeHash.Bytes() |
||||
} |
||||
if acct.Root == (common.Hash{}) { |
||||
acct.Root = types.EmptyRootHash |
||||
} |
||||
return acct, nil |
||||
} |
||||
|
||||
// Storage implements Reader, retrieving the storage slot specified by the
|
||||
// address and slot key.
|
||||
//
|
||||
// An error will be returned if the associated snapshot is already stale or
|
||||
// the requested storage slot is not yet covered by the snapshot.
|
||||
//
|
||||
// The returned storage slot might be empty if it's not existent.
|
||||
func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) { |
||||
addrHash := crypto.HashData(r.buff, addr.Bytes()) |
||||
slotHash := crypto.HashData(r.buff, key.Bytes()) |
||||
ret, err := r.snap.Storage(addrHash, slotHash) |
||||
if err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
if len(ret) == 0 { |
||||
return common.Hash{}, nil |
||||
} |
||||
// Perform the rlp-decode as the slot value is RLP-encoded in the state
|
||||
// snapshot.
|
||||
_, content, _, err := rlp.Split(ret) |
||||
if err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
var value common.Hash |
||||
value.SetBytes(content) |
||||
return value, nil |
||||
} |
||||
|
||||
// Copy implements Reader, returning a deep-copied snap reader.
|
||||
func (r *stateReader) Copy() Reader { |
||||
return &stateReader{ |
||||
snap: r.snap, |
||||
buff: crypto.NewKeccakState(), |
||||
} |
||||
} |
||||
|
||||
// trieReader implements the Reader interface, providing functions to access
|
||||
// state from the referenced trie.
|
||||
type trieReader struct { |
||||
root common.Hash // State root which uniquely represent a state
|
||||
db *triedb.Database // Database for loading trie
|
||||
buff crypto.KeccakState // Buffer for keccak256 hashing
|
||||
mainTrie Trie // Main trie, resolved in constructor
|
||||
subRoots map[common.Address]common.Hash // Set of storage roots, cached when the account is resolved
|
||||
subTries map[common.Address]Trie // Group of storage tries, cached when it's resolved
|
||||
} |
||||
|
||||
// trieReader constructs a trie reader of the specific state. An error will be
|
||||
// returned if the associated trie specified by root is not existent.
|
||||
func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCache) (*trieReader, error) { |
||||
var ( |
||||
tr Trie |
||||
err error |
||||
) |
||||
if !db.IsVerkle() { |
||||
tr, err = trie.NewStateTrie(trie.StateTrieID(root), db) |
||||
} else { |
||||
tr, err = trie.NewVerkleTrie(root, db, cache) |
||||
} |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return &trieReader{ |
||||
root: root, |
||||
db: db, |
||||
buff: crypto.NewKeccakState(), |
||||
mainTrie: tr, |
||||
subRoots: make(map[common.Address]common.Hash), |
||||
subTries: make(map[common.Address]Trie), |
||||
}, nil |
||||
} |
||||
|
||||
// Account implements Reader, retrieving the account specified by the address.
|
||||
//
|
||||
// An error will be returned if the trie state is corrupted. An nil account
|
||||
// will be returned if it's not existent in the trie.
|
||||
func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) { |
||||
account, err := r.mainTrie.GetAccount(addr) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if account == nil { |
||||
r.subRoots[addr] = types.EmptyRootHash |
||||
} else { |
||||
r.subRoots[addr] = account.Root |
||||
} |
||||
return account, nil |
||||
} |
||||
|
||||
// Storage implements Reader, retrieving the storage slot specified by the
|
||||
// address and slot key.
|
||||
//
|
||||
// An error will be returned if the trie state is corrupted. An empty storage
|
||||
// slot will be returned if it's not existent in the trie.
|
||||
func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) { |
||||
var ( |
||||
tr Trie |
||||
found bool |
||||
value common.Hash |
||||
) |
||||
if r.db.IsVerkle() { |
||||
tr = r.mainTrie |
||||
} else { |
||||
tr, found = r.subTries[addr] |
||||
if !found { |
||||
root, ok := r.subRoots[addr] |
||||
|
||||
// The storage slot is accessed without account caching. It's unexpected
|
||||
// behavior but try to resolve the account first anyway.
|
||||
if !ok { |
||||
_, err := r.Account(addr) |
||||
if err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
root = r.subRoots[addr] |
||||
} |
||||
var err error |
||||
tr, err = trie.NewStateTrie(trie.StorageTrieID(r.root, crypto.HashData(r.buff, addr.Bytes()), root), r.db) |
||||
if err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
r.subTries[addr] = tr |
||||
} |
||||
} |
||||
ret, err := tr.GetStorage(addr, key.Bytes()) |
||||
if err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
value.SetBytes(ret) |
||||
return value, nil |
||||
} |
||||
|
||||
// Copy implements Reader, returning a deep-copied trie reader.
|
||||
func (r *trieReader) Copy() Reader { |
||||
tries := make(map[common.Address]Trie) |
||||
for addr, tr := range r.subTries { |
||||
tries[addr] = mustCopyTrie(tr) |
||||
} |
||||
return &trieReader{ |
||||
root: r.root, |
||||
db: r.db, |
||||
buff: crypto.NewKeccakState(), |
||||
mainTrie: mustCopyTrie(r.mainTrie), |
||||
subRoots: maps.Clone(r.subRoots), |
||||
subTries: tries, |
||||
} |
||||
} |
||||
|
||||
// multiReader is the aggregation of a list of Reader interface, providing state
|
||||
// access by leveraging all readers. The checking priority is determined by the
|
||||
// position in the reader list.
|
||||
type multiReader struct { |
||||
readers []Reader // List of readers, sorted by checking priority
|
||||
} |
||||
|
||||
// newMultiReader constructs a multiReader instance with the given readers. The
|
||||
// priority among readers is assumed to be sorted. Note, it must contain at least
|
||||
// one reader for constructing a multiReader.
|
||||
func newMultiReader(readers ...Reader) (*multiReader, error) { |
||||
if len(readers) == 0 { |
||||
return nil, errors.New("empty reader set") |
||||
} |
||||
return &multiReader{ |
||||
readers: readers, |
||||
}, nil |
||||
} |
||||
|
||||
// Account implementing Reader interface, retrieving the account associated with
|
||||
// a particular address.
|
||||
//
|
||||
// - Returns a nil account if it does not exist
|
||||
// - Returns an error only if an unexpected issue occurs
|
||||
// - The returned account is safe to modify after the call
|
||||
func (r *multiReader) Account(addr common.Address) (*types.StateAccount, error) { |
||||
var errs []error |
||||
for _, reader := range r.readers { |
||||
acct, err := reader.Account(addr) |
||||
if err == nil { |
||||
return acct, nil |
||||
} |
||||
errs = append(errs, err) |
||||
} |
||||
return nil, errors.Join(errs...) |
||||
} |
||||
|
||||
// Storage implementing Reader interface, retrieving the storage slot associated
|
||||
// with a particular account address and slot key.
|
||||
//
|
||||
// - Returns an empty slot if it does not exist
|
||||
// - Returns an error only if an unexpected issue occurs
|
||||
// - The returned storage slot is safe to modify after the call
|
||||
func (r *multiReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { |
||||
var errs []error |
||||
for _, reader := range r.readers { |
||||
slot, err := reader.Storage(addr, slot) |
||||
if err == nil { |
||||
return slot, nil |
||||
} |
||||
errs = append(errs, err) |
||||
} |
||||
return common.Hash{}, errors.Join(errs...) |
||||
} |
||||
|
||||
// Copy implementing Reader interface, returning a deep-copied state reader.
|
||||
func (r *multiReader) Copy() Reader { |
||||
var readers []Reader |
||||
for _, reader := range r.readers { |
||||
readers = append(readers, reader.Copy()) |
||||
} |
||||
return &multiReader{readers: readers} |
||||
} |
@ -0,0 +1,103 @@ |
||||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/binary" |
||||
"fmt" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/common/hexutil" |
||||
"github.com/ethereum/go-ethereum/rlp" |
||||
) |
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type Deposit -field-override depositMarshaling -out gen_deposit_json.go
|
||||
|
||||
// Deposit contains EIP-6110 deposit data.
|
||||
type Deposit struct { |
||||
PublicKey [48]byte `json:"pubkey"` // public key of validator
|
||||
WithdrawalCredentials common.Hash `json:"withdrawalCredentials"` // beneficiary of the validator funds
|
||||
Amount uint64 `json:"amount"` // deposit size in Gwei
|
||||
Signature [96]byte `json:"signature"` // signature over deposit msg
|
||||
Index uint64 `json:"index"` // deposit count value
|
||||
} |
||||
|
||||
// field type overrides for gencodec
|
||||
type depositMarshaling struct { |
||||
PublicKey hexutil.Bytes |
||||
WithdrawalCredentials hexutil.Bytes |
||||
Amount hexutil.Uint64 |
||||
Signature hexutil.Bytes |
||||
Index hexutil.Uint64 |
||||
} |
||||
|
||||
// Deposits implements DerivableList for requests.
|
||||
type Deposits []*Deposit |
||||
|
||||
// Len returns the length of s.
|
||||
func (s Deposits) Len() int { return len(s) } |
||||
|
||||
// EncodeIndex encodes the i'th deposit to s.
|
||||
func (s Deposits) EncodeIndex(i int, w *bytes.Buffer) { |
||||
rlp.Encode(w, s[i]) |
||||
} |
||||
|
||||
// UnpackIntoDeposit unpacks a serialized DepositEvent.
|
||||
func UnpackIntoDeposit(data []byte) (*Deposit, error) { |
||||
if len(data) != 576 { |
||||
return nil, fmt.Errorf("deposit wrong length: want 576, have %d", len(data)) |
||||
} |
||||
var d Deposit |
||||
// The ABI encodes the position of dynamic elements first. Since there are 5
|
||||
// elements, skip over the positional data. The first 32 bytes of dynamic
|
||||
// elements also encode their actual length. Skip over that value too.
|
||||
b := 32*5 + 32 |
||||
// PublicKey is the first element. ABI encoding pads values to 32 bytes, so
|
||||
// despite BLS public keys being length 48, the value length here is 64. Then
|
||||
// skip over the next length value.
|
||||
copy(d.PublicKey[:], data[b:b+48]) |
||||
b += 48 + 16 + 32 |
||||
// WithdrawalCredentials is 32 bytes. Read that value then skip over next
|
||||
// length.
|
||||
copy(d.WithdrawalCredentials[:], data[b:b+32]) |
||||
b += 32 + 32 |
||||
// Amount is 8 bytes, but it is padded to 32. Skip over it and the next
|
||||
// length.
|
||||
d.Amount = binary.LittleEndian.Uint64(data[b : b+8]) |
||||
b += 8 + 24 + 32 |
||||
// Signature is 96 bytes. Skip over it and the next length.
|
||||
copy(d.Signature[:], data[b:b+96]) |
||||
b += 96 + 32 |
||||
// Amount is 8 bytes.
|
||||
d.Index = binary.LittleEndian.Uint64(data[b : b+8]) |
||||
|
||||
return &d, nil |
||||
} |
||||
|
||||
func (d *Deposit) requestType() byte { return DepositRequestType } |
||||
func (d *Deposit) encode(b *bytes.Buffer) error { return rlp.Encode(b, d) } |
||||
func (d *Deposit) decode(input []byte) error { return rlp.DecodeBytes(input, d) } |
||||
func (d *Deposit) copy() RequestData { |
||||
return &Deposit{ |
||||
PublicKey: d.PublicKey, |
||||
WithdrawalCredentials: d.WithdrawalCredentials, |
||||
Amount: d.Amount, |
||||
Signature: d.Signature, |
||||
Index: d.Index, |
||||
} |
||||
} |
@ -0,0 +1,93 @@ |
||||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types |
||||
|
||||
import ( |
||||
"encoding/binary" |
||||
"reflect" |
||||
"testing" |
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi" |
||||
"github.com/ethereum/go-ethereum/common" |
||||
) |
||||
|
||||
var ( |
||||
depositABI = abi.ABI{Methods: map[string]abi.Method{"DepositEvent": depositEvent}} |
||||
bytesT, _ = abi.NewType("bytes", "", nil) |
||||
depositEvent = abi.NewMethod("DepositEvent", "DepositEvent", abi.Function, "", false, false, []abi.Argument{ |
||||
{Name: "pubkey", Type: bytesT, Indexed: false}, |
||||
{Name: "withdrawal_credentials", Type: bytesT, Indexed: false}, |
||||
{Name: "amount", Type: bytesT, Indexed: false}, |
||||
{Name: "signature", Type: bytesT, Indexed: false}, |
||||
{Name: "index", Type: bytesT, Indexed: false}}, nil, |
||||
) |
||||
) |
||||
|
||||
// FuzzUnpackIntoDeposit tries roundtrip packing and unpacking of deposit events.
|
||||
func FuzzUnpackIntoDeposit(f *testing.F) { |
||||
for _, tt := range []struct { |
||||
pubkey string |
||||
wxCred string |
||||
amount string |
||||
sig string |
||||
index string |
||||
}{ |
||||
{ |
||||
pubkey: "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", |
||||
wxCred: "2222222222222222222222222222222222222222222222222222222222222222", |
||||
amount: "3333333333333333", |
||||
sig: "444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444", |
||||
index: "5555555555555555", |
||||
}, |
||||
} { |
||||
f.Add(common.FromHex(tt.pubkey), common.FromHex(tt.wxCred), common.FromHex(tt.amount), common.FromHex(tt.sig), common.FromHex(tt.index)) |
||||
} |
||||
|
||||
f.Fuzz(func(t *testing.T, p []byte, w []byte, a []byte, s []byte, i []byte) { |
||||
var ( |
||||
pubkey [48]byte |
||||
wxCred [32]byte |
||||
amount [8]byte |
||||
sig [96]byte |
||||
index [8]byte |
||||
) |
||||
copy(pubkey[:], p) |
||||
copy(wxCred[:], w) |
||||
copy(amount[:], a) |
||||
copy(sig[:], s) |
||||
copy(index[:], i) |
||||
|
||||
want := Deposit{ |
||||
PublicKey: pubkey, |
||||
WithdrawalCredentials: wxCred, |
||||
Amount: binary.LittleEndian.Uint64(amount[:]), |
||||
Signature: sig, |
||||
Index: binary.LittleEndian.Uint64(index[:]), |
||||
} |
||||
out, err := depositABI.Pack("DepositEvent", want.PublicKey[:], want.WithdrawalCredentials[:], amount[:], want.Signature[:], index[:]) |
||||
if err != nil { |
||||
t.Fatalf("error packing deposit: %v", err) |
||||
} |
||||
got, err := UnpackIntoDeposit(out[4:]) |
||||
if err != nil { |
||||
t.Errorf("error unpacking deposit: %v", err) |
||||
} |
||||
if !reflect.DeepEqual(want, *got) { |
||||
t.Errorf("roundtrip failed: want %v, got %v", want, got) |
||||
} |
||||
}) |
||||
} |
@ -0,0 +1,70 @@ |
||||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||
|
||||
package types |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil" |
||||
) |
||||
|
||||
var _ = (*depositMarshaling)(nil) |
||||
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (d Deposit) MarshalJSON() ([]byte, error) { |
||||
type Deposit struct { |
||||
PublicKey hexutil.Bytes `json:"pubkey"` |
||||
WithdrawalCredentials hexutil.Bytes `json:"withdrawalCredentials"` |
||||
Amount hexutil.Uint64 `json:"amount"` |
||||
Signature hexutil.Bytes `json:"signature"` |
||||
Index hexutil.Uint64 `json:"index"` |
||||
} |
||||
var enc Deposit |
||||
enc.PublicKey = d.PublicKey[:] |
||||
enc.WithdrawalCredentials = d.WithdrawalCredentials[:] |
||||
enc.Amount = hexutil.Uint64(d.Amount) |
||||
enc.Signature = d.Signature[:] |
||||
enc.Index = hexutil.Uint64(d.Index) |
||||
return json.Marshal(&enc) |
||||
} |
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (d *Deposit) UnmarshalJSON(input []byte) error { |
||||
type Deposit struct { |
||||
PublicKey *hexutil.Bytes `json:"pubkey"` |
||||
WithdrawalCredentials *hexutil.Bytes `json:"withdrawalCredentials"` |
||||
Amount *hexutil.Uint64 `json:"amount"` |
||||
Signature *hexutil.Bytes `json:"signature"` |
||||
Index *hexutil.Uint64 `json:"index"` |
||||
} |
||||
var dec Deposit |
||||
if err := json.Unmarshal(input, &dec); err != nil { |
||||
return err |
||||
} |
||||
if dec.PublicKey != nil { |
||||
if len(*dec.PublicKey) != len(d.PublicKey) { |
||||
return errors.New("field 'pubkey' has wrong length, need 48 items") |
||||
} |
||||
copy(d.PublicKey[:], *dec.PublicKey) |
||||
} |
||||
if dec.WithdrawalCredentials != nil { |
||||
if len(*dec.WithdrawalCredentials) != len(d.WithdrawalCredentials) { |
||||
return errors.New("field 'withdrawalCredentials' has wrong length, need 32 items") |
||||
} |
||||
copy(d.WithdrawalCredentials[:], *dec.WithdrawalCredentials) |
||||
} |
||||
if dec.Amount != nil { |
||||
d.Amount = uint64(*dec.Amount) |
||||
} |
||||
if dec.Signature != nil { |
||||
if len(*dec.Signature) != len(d.Signature) { |
||||
return errors.New("field 'signature' has wrong length, need 96 items") |
||||
} |
||||
copy(d.Signature[:], *dec.Signature) |
||||
} |
||||
if dec.Index != nil { |
||||
d.Index = uint64(*dec.Index) |
||||
} |
||||
return nil |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue