merge geth v1.12.2 into develop

This commit is contained in:
Arpit Temani 2023-08-18 14:05:34 +05:30
commit b343cffdb4
596 changed files with 37249 additions and 33711 deletions

3
.gitmodules vendored
View file

@ -6,6 +6,3 @@
path = tests/evm-benchmarks path = tests/evm-benchmarks
url = https://github.com/ipsilon/evm-benchmarks url = https://github.com/ipsilon/evm-benchmarks
shallow = true shallow = true
[submodule "tests/testdata"]
path = tests/testdata
url = https://github.com/ethereum/tests.git

View file

@ -245,6 +245,17 @@ func (abi *ABI) EventByID(topic common.Hash) (*Event, error) {
return nil, fmt.Errorf("no event with id: %#x", topic.Hex()) return nil, fmt.Errorf("no event with id: %#x", topic.Hex())
} }
// ErrorByID looks up an error by the 4-byte id,
// returns nil if none found.
func (abi *ABI) ErrorByID(sigdata [4]byte) (*Error, error) {
for _, errABI := range abi.Errors {
if bytes.Equal(errABI.ID[:4], sigdata[:]) {
return &errABI, nil
}
}
return nil, fmt.Errorf("no error with id: %#x", sigdata[:])
}
// HasFallback returns an indicator whether a fallback function is included. // HasFallback returns an indicator whether a fallback function is included.
func (abi *ABI) HasFallback() bool { func (abi *ABI) HasFallback() bool {
return abi.Fallback.Type == Fallback return abi.Fallback.Type == Fallback

View file

@ -1148,6 +1148,34 @@ func TestABI_EventById(t *testing.T) {
} }
} }
func TestABI_ErrorByID(t *testing.T) {
abi, err := JSON(strings.NewReader(`[
{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"MyError1","type":"error"},
{"inputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"x","type":"tuple"},{"internalType":"address","name":"y","type":"address"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"z","type":"tuple"}],"name":"MyError2","type":"error"},
{"inputs":[{"internalType":"uint256[]","name":"x","type":"uint256[]"}],"name":"MyError3","type":"error"}
]`))
if err != nil {
t.Fatal(err)
}
for name, m := range abi.Errors {
a := fmt.Sprintf("%v", &m)
var id [4]byte
copy(id[:], m.ID[:4])
m2, err := abi.ErrorByID(id)
if err != nil {
t.Fatalf("Failed to look up ABI error: %v", err)
}
b := fmt.Sprintf("%v", m2)
if a != b {
t.Errorf("Error %v (id %x) not 'findable' by id in ABI", name, id)
}
}
// test unsuccessful lookups
if _, err = abi.ErrorByID([4]byte{}); err == nil {
t.Error("Expected error: no error with this id")
}
}
// TestDoubleDuplicateMethodNames checks that if transfer0 already exists, there won't be a name // TestDoubleDuplicateMethodNames checks that if transfer0 already exists, there won't be a name
// conflict and that the second transfer method will be renamed transfer1. // conflict and that the second transfer method will be renamed transfer1.
func TestDoubleDuplicateMethodNames(t *testing.T) { func TestDoubleDuplicateMethodNames(t *testing.T) {

View file

@ -29,7 +29,7 @@ import (
var ( var (
// ErrNoCode is returned by call and transact operations for which the requested // ErrNoCode is returned by call and transact operations for which the requested
// recipient contract to operate on does not exist in the state db or does not // recipient contract to operate on does not exist in the state db or does not
// have any code associated with it (i.e. suicided). // have any code associated with it (i.e. self-destructed).
ErrNoCode = errors.New("no contract code at given address") ErrNoCode = errors.New("no contract code at given address")
// ErrNoPendingState is raised when attempting to perform a pending state action // ErrNoPendingState is raised when attempting to perform a pending state action

View file

@ -718,11 +718,10 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
// Get the last block // Get the last block
block, err := b.blockByHash(ctx, b.pendingBlock.ParentHash()) block, err := b.blockByHash(ctx, b.pendingBlock.ParentHash())
if err != nil { if err != nil {
return fmt.Errorf("could not fetch parent") return errors.New("could not fetch parent")
} }
// Check transaction validity // Check transaction validity
signer := types.MakeSigner(b.blockchain.Config(), block.Number()) signer := types.MakeSigner(b.blockchain.Config(), block.Number(), block.Time())
sender, err := types.Sender(signer, tx) sender, err := types.Sender(signer, tx)
if err != nil { if err != nil {
return fmt.Errorf("invalid transaction: %v", err) return fmt.Errorf("invalid transaction: %v", err)
@ -862,7 +861,7 @@ func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
// Get the last block // Get the last block
block := b.blockchain.GetBlockByHash(b.pendingBlock.ParentHash()) block := b.blockchain.GetBlockByHash(b.pendingBlock.ParentHash())
if block == nil { if block == nil {
return fmt.Errorf("could not find parent") return errors.New("could not find parent")
} }
blocks, _ := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { blocks, _ := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
@ -934,8 +933,11 @@ func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (typ
if number == nil { if number == nil {
return nil, nil return nil, nil
} }
header := rawdb.ReadHeader(fb.db, hash, *number)
return rawdb.ReadReceipts(fb.db, hash, *number, fb.bc.Config()), nil if header == nil {
return nil, nil
}
return rawdb.ReadReceipts(fb.db, hash, *number, header.Time, fb.bc.Config()), nil
} }
func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) {

View file

@ -177,6 +177,7 @@ func TestAdjustTime(t *testing.T) {
func TestNewAdjustTimeFail(t *testing.T) { func TestNewAdjustTimeFail(t *testing.T) {
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
defer sim.blockchain.Stop()
// Create tx and send // Create tx and send
head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough

View file

@ -135,13 +135,19 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
// Normalize the method for capital cases and non-anonymous inputs/outputs // Normalize the method for capital cases and non-anonymous inputs/outputs
normalized := original normalized := original
normalizedName := methodNormalizer[lang](alias(aliases, original.Name)) normalizedName := methodNormalizer[lang](alias(aliases, original.Name))
// Ensure there is no duplicated identifier // Ensure there is no duplicated identifier
var identifiers = callIdentifiers var identifiers = callIdentifiers
if !original.IsConstant() { if !original.IsConstant() {
identifiers = transactIdentifiers identifiers = transactIdentifiers
} }
// Name shouldn't start with a digit. It will make the generated code invalid.
if len(normalizedName) > 0 && unicode.IsDigit(rune(normalizedName[0])) {
normalizedName = fmt.Sprintf("M%s", normalizedName)
normalizedName = abi.ResolveNameConflict(normalizedName, func(name string) bool {
_, ok := identifiers[name]
return ok
})
}
if identifiers[normalizedName] { if identifiers[normalizedName] {
return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName) return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName)
} }
@ -192,6 +198,14 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
// Ensure there is no duplicated identifier // Ensure there is no duplicated identifier
normalizedName := methodNormalizer[lang](alias(aliases, original.Name)) normalizedName := methodNormalizer[lang](alias(aliases, original.Name))
// Name shouldn't start with a digit. It will make the generated code invalid.
if len(normalizedName) > 0 && unicode.IsDigit(rune(normalizedName[0])) {
normalizedName = fmt.Sprintf("E%s", normalizedName)
normalizedName = abi.ResolveNameConflict(normalizedName, func(name string) bool {
_, ok := eventIdentifiers[name]
return ok
})
}
if eventIdentifiers[normalizedName] { if eventIdentifiers[normalizedName] {
return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName) return "", fmt.Errorf("duplicated identifier \"%s\"(normalized \"%s\"), use --alias for renaming", original.Name, normalizedName)
} }

View file

@ -2038,6 +2038,29 @@ var bindTests = []struct {
t.Errorf("error deploying the contract: %v", err) t.Errorf("error deploying the contract: %v", err)
} }
`, `,
}, {
name: "NumericMethodName",
contract: `
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;
contract NumericMethodName {
event _1TestEvent(address _param);
function _1test() public pure {}
function __1test() public pure {}
function __2test() public pure {}
}
`,
bytecode: []string{"0x6080604052348015600f57600080fd5b5060958061001e6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80639d993132146041578063d02767c7146049578063ffa02795146051575b600080fd5b60476059565b005b604f605b565b005b6057605d565b005b565b565b56fea26469706673582212200382ca602dff96a7e2ba54657985e2b4ac423a56abe4a1f0667bc635c4d4371f64736f6c63430008110033"},
abi: []string{`[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_param","type":"address"}],"name":"_1TestEvent","type":"event"},{"inputs":[],"name":"_1test","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"__1test","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"__2test","outputs":[],"stateMutability":"pure","type":"function"}]`},
imports: `
"github.com/ethereum/go-ethereum/common"
`,
tester: `
if b, err := NewNumericMethodName(common.Address{}, nil); b == nil || err != nil {
t.Fatalf("combined binding (%v) nil or error (%v) not nil", b, nil)
}
`,
}, },
} }

View file

@ -32,7 +32,7 @@ type Error struct {
str string str string
// Sig contains the string signature according to the ABI spec. // Sig contains the string signature according to the ABI spec.
// e.g. error foo(uint32 a, int b) = "foo(uint32,int256)" // e.g. error foo(uint32 a, int b) = "foo(uint32,int256)"
// Please note that "int" is substitute for its canonical representation "int256" // Please note that "int" is substitute for its canonical representation "int256"
Sig string Sig string
@ -79,7 +79,7 @@ func NewError(name string, inputs Arguments) Error {
} }
} }
func (e *Error) String() string { func (e Error) String() string {
return e.str return e.str
} }

View file

@ -246,7 +246,7 @@ func mapArgNamesToStructFields(argNames []string, value reflect.Value) (map[stri
structFieldName := ToCamelCase(argName) structFieldName := ToCamelCase(argName)
if structFieldName == "" { if structFieldName == "" {
return nil, fmt.Errorf("abi: purely underscored output cannot unpack to struct") return nil, errors.New("abi: purely underscored output cannot unpack to struct")
} }
// this abi has already been paired, skip it... unless there exists another, yet unassigned // this abi has already been paired, skip it... unless there exists another, yet unassigned

View file

@ -17,6 +17,7 @@
package abi package abi
import ( import (
"errors"
"fmt" "fmt"
) )
@ -40,7 +41,7 @@ func isIdentifierSymbol(c byte) bool {
func parseToken(unescapedSelector string, isIdent bool) (string, string, error) { func parseToken(unescapedSelector string, isIdent bool) (string, string, error) {
if len(unescapedSelector) == 0 { if len(unescapedSelector) == 0 {
return "", "", fmt.Errorf("empty token") return "", "", errors.New("empty token")
} }
firstChar := unescapedSelector[0] firstChar := unescapedSelector[0]
@ -126,7 +127,7 @@ func parseCompositeType(unescapedSelector string) ([]interface{}, string, error)
func parseType(unescapedSelector string) (interface{}, string, error) { func parseType(unescapedSelector string) (interface{}, string, error) {
if len(unescapedSelector) == 0 { if len(unescapedSelector) == 0 {
return nil, "", fmt.Errorf("empty type") return nil, "", errors.New("empty type")
} }
if unescapedSelector[0] == '(' { if unescapedSelector[0] == '(' {

View file

@ -70,7 +70,7 @@ var (
func NewType(t string, internalType string, components []ArgumentMarshaling) (typ Type, err error) { func NewType(t string, internalType string, components []ArgumentMarshaling) (typ Type, err error) {
// check that array brackets are equal if they exist // check that array brackets are equal if they exist
if strings.Count(t, "[") != strings.Count(t, "]") { if strings.Count(t, "[") != strings.Count(t, "]") {
return Type{}, fmt.Errorf("invalid arg type in abi") return Type{}, errors.New("invalid arg type in abi")
} }
typ.stringKind = t typ.stringKind = t
@ -113,7 +113,7 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
typ.stringKind = embeddedType.stringKind + sliced typ.stringKind = embeddedType.stringKind + sliced
} else { } else {
return Type{}, fmt.Errorf("invalid formatting of array type") return Type{}, errors.New("invalid formatting of array type")
} }
return typ, err return typ, err
@ -380,7 +380,7 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
} }
} }
// requireLengthPrefix returns whether the type requires any sort of length // requiresLengthPrefix returns whether the type requires any sort of length
// prefixing. // prefixing.
func (t Type) requiresLengthPrefix() bool { func (t Type) requiresLengthPrefix() bool {
return t.T == StringTy || t.T == BytesTy || t.T == SliceTy return t.T == StringTy || t.T == BytesTy || t.T == SliceTy

View file

@ -18,6 +18,7 @@ package abi
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"math" "math"
"math/big" "math/big"
@ -137,7 +138,7 @@ func readBool(word []byte) (bool, error) {
// readFunctionType enforces that standard by always presenting it as a 24-array (address + sig = 24 bytes) // readFunctionType enforces that standard by always presenting it as a 24-array (address + sig = 24 bytes)
func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) { func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) {
if t.T != FunctionTy { if t.T != FunctionTy {
return [24]byte{}, fmt.Errorf("abi: invalid type in call to make function type byte array") return [24]byte{}, errors.New("abi: invalid type in call to make function type byte array")
} }
if garbage := binary.BigEndian.Uint64(word[24:32]); garbage != 0 { if garbage := binary.BigEndian.Uint64(word[24:32]); garbage != 0 {
@ -152,7 +153,7 @@ func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) {
// ReadFixedBytes uses reflection to create a fixed array to be read from. // ReadFixedBytes uses reflection to create a fixed array to be read from.
func ReadFixedBytes(t Type, word []byte) (interface{}, error) { func ReadFixedBytes(t Type, word []byte) (interface{}, error) {
if t.T != FixedBytesTy { if t.T != FixedBytesTy {
return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array") return nil, errors.New("abi: invalid type in call to make fixed byte array")
} }
// convert // convert
array := reflect.New(t.GetType()).Elem() array := reflect.New(t.GetType()).Elem()
@ -182,7 +183,7 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
// declare our array // declare our array
refSlice = reflect.New(t.GetType()).Elem() refSlice = reflect.New(t.GetType()).Elem()
} else { } else {
return nil, fmt.Errorf("abi: invalid type in array/slice unpacking stage") return nil, errors.New("abi: invalid type in array/slice unpacking stage")
} }
// Arrays have packed elements, resulting in longer unpack steps. // Arrays have packed elements, resulting in longer unpack steps.

View file

@ -17,6 +17,7 @@
package external package external
import ( import (
"errors"
"fmt" "fmt"
"math/big" "math/big"
"sync" "sync"
@ -102,11 +103,11 @@ func (api *ExternalSigner) Status() (string, error) {
} }
func (api *ExternalSigner) Open(passphrase string) error { func (api *ExternalSigner) Open(passphrase string) error {
return fmt.Errorf("operation not supported on external signers") return errors.New("operation not supported on external signers")
} }
func (api *ExternalSigner) Close() error { func (api *ExternalSigner) Close() error {
return fmt.Errorf("operation not supported on external signers") return errors.New("operation not supported on external signers")
} }
func (api *ExternalSigner) Accounts() []accounts.Account { func (api *ExternalSigner) Accounts() []accounts.Account {
@ -156,7 +157,7 @@ func (api *ExternalSigner) Contains(account accounts.Account) bool {
} }
func (api *ExternalSigner) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) { func (api *ExternalSigner) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) {
return accounts.Account{}, fmt.Errorf("operation not supported on external signers") return accounts.Account{}, errors.New("operation not supported on external signers")
} }
func (api *ExternalSigner) SelfDerive(bases []accounts.DerivationPath, chain ethereum.ChainStateReader) { func (api *ExternalSigner) SelfDerive(bases []accounts.DerivationPath, chain ethereum.ChainStateReader) {
@ -265,14 +266,14 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
} }
func (api *ExternalSigner) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) { func (api *ExternalSigner) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) {
return []byte{}, fmt.Errorf("password-operations not supported on external signers") return []byte{}, errors.New("password-operations not supported on external signers")
} }
func (api *ExternalSigner) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { func (api *ExternalSigner) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
return nil, fmt.Errorf("password-operations not supported on external signers") return nil, errors.New("password-operations not supported on external signers")
} }
func (api *ExternalSigner) SignDataWithPassphrase(account accounts.Account, passphrase, mimeType string, data []byte) ([]byte, error) { func (api *ExternalSigner) SignDataWithPassphrase(account accounts.Account, passphrase, mimeType string, data []byte) ([]byte, error) {
return nil, fmt.Errorf("password-operations not supported on external signers") return nil, errors.New("password-operations not supported on external signers")
} }
func (api *ExternalSigner) listAccounts() ([]common.Address, error) { func (api *ExternalSigner) listAccounts() ([]common.Address, error) {

View file

@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"golang.org/x/exp/slices"
) )
// Minimum amount of time between cache reloads. This limit applies if the platform does // Minimum amount of time between cache reloads. This limit applies if the platform does
@ -39,11 +40,10 @@ import (
// exist yet, the code will attempt to create a watcher at most this often. // exist yet, the code will attempt to create a watcher at most this often.
const minReloadInterval = 2 * time.Second const minReloadInterval = 2 * time.Second
type accountsByURL []accounts.Account // byURL defines the sorting order for accounts.
func byURL(a, b accounts.Account) int {
func (s accountsByURL) Len() int { return len(s) } return a.URL.Cmp(b.URL)
func (s accountsByURL) Less(i, j int) bool { return s[i].URL.Cmp(s[j].URL) < 0 } }
func (s accountsByURL) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// AmbiguousAddrError is returned when attempting to unlock // AmbiguousAddrError is returned when attempting to unlock
// an address for which more than one file exists. // an address for which more than one file exists.
@ -69,7 +69,7 @@ type accountCache struct {
keydir string keydir string
watcher *watcher watcher *watcher
mu sync.Mutex mu sync.Mutex
all accountsByURL all []accounts.Account
byAddr map[common.Address][]accounts.Account byAddr map[common.Address][]accounts.Account
throttle *time.Timer throttle *time.Timer
notify chan struct{} notify chan struct{}
@ -206,8 +206,7 @@ func (ac *accountCache) find(a accounts.Account) (accounts.Account, error) {
default: default:
err := &AmbiguousAddrError{Addr: a.Address, Matches: make([]accounts.Account, len(matches))} err := &AmbiguousAddrError{Addr: a.Address, Matches: make([]accounts.Account, len(matches))}
copy(err.Matches, matches) copy(err.Matches, matches)
sort.Sort(accountsByURL(err.Matches)) slices.SortFunc(err.Matches, byURL)
return accounts.Account{}, err return accounts.Account{}, err
} }
} }

View file

@ -17,12 +17,12 @@
package keystore package keystore
import ( import (
"errors"
"fmt" "fmt"
"math/rand" "math/rand"
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"sort"
"testing" "testing"
"time" "time"
@ -30,6 +30,7 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"golang.org/x/exp/slices"
) )
var ( var (
@ -75,7 +76,7 @@ func waitForAccounts(wantAccounts []accounts.Account, ks *KeyStore) error {
select { select {
case <-ks.changes: case <-ks.changes:
default: default:
return fmt.Errorf("wasn't notified of new accounts") return errors.New("wasn't notified of new accounts")
} }
return nil return nil
@ -212,8 +213,7 @@ func TestCacheAddDeleteOrder(t *testing.T) {
// Check that the account list is sorted by filename. // Check that the account list is sorted by filename.
wantAccounts := make([]accounts.Account, len(accs)) wantAccounts := make([]accounts.Account, len(accs))
copy(wantAccounts, accs) copy(wantAccounts, accs)
sort.Sort(accountsByURL(wantAccounts)) slices.SortFunc(wantAccounts, byURL)
list := cache.accounts() list := cache.accounts()
if !reflect.DeepEqual(list, wantAccounts) { if !reflect.DeepEqual(list, wantAccounts) {
t.Fatalf("got accounts: %s\nwant %s", spew.Sdump(accs), spew.Sdump(wantAccounts)) t.Fatalf("got accounts: %s\nwant %s", spew.Sdump(accs), spew.Sdump(wantAccounts))

View file

@ -20,7 +20,6 @@ import (
"math/rand" "math/rand"
"os" "os"
"runtime" "runtime"
"sort"
"strings" "strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -31,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"golang.org/x/exp/slices"
) )
var testSigData = make([]byte, 32) var testSigData = make([]byte, 32)
@ -439,9 +439,7 @@ func TestImportRace(t *testing.T) {
} }
_, ks2 := tmpKeyStore(t, true) _, ks2 := tmpKeyStore(t, true)
var atom atomic.Uint32
var atom uint32
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(2) wg.Add(2)
@ -451,13 +449,12 @@ func TestImportRace(t *testing.T) {
defer wg.Done() defer wg.Done()
if _, err := ks2.Import(json, "new", "new"); err != nil { if _, err := ks2.Import(json, "new", "new"); err != nil {
atomic.AddUint32(&atom, 1) atom.Add(1)
} }
}() }()
} }
wg.Wait() wg.Wait()
if atom.Load() != 1 {
if atom != 1 {
t.Errorf("Import is racy") t.Errorf("Import is racy")
} }
} }
@ -473,9 +470,7 @@ func checkAccounts(t *testing.T, live map[common.Address]accounts.Account, walle
for _, account := range live { for _, account := range live {
liveList = append(liveList, account) liveList = append(liveList, account)
} }
slices.SortFunc(liveList, byURL)
sort.Sort(accountsByURL(liveList))
for j, wallet := range wallets { for j, wallet := range wallets {
if accs := wallet.Accounts(); len(accs) != 1 { if accs := wallet.Accounts(); len(accs) != 1 {
t.Errorf("wallet %d: contains invalid number of accounts: have %d, want 1", j, len(accs)) t.Errorf("wallet %d: contains invalid number of accounts: have %d, want 1", j, len(accs))

View file

@ -241,12 +241,13 @@ func DecryptKey(keyjson []byte, auth string) (*Key, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
key, err := crypto.ToECDSA(keyBytes)
key := crypto.ToECDSAUnsafe(keyBytes) if err != nil {
return nil, fmt.Errorf("invalid key: %w", err)
}
id, err := uuid.FromBytes(keyId) id, err := uuid.FromBytes(keyId)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("invalid UUID: %w", err)
} }
return &Key{ return &Key{

View file

@ -24,6 +24,7 @@ import (
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"crypto/sha512" "crypto/sha512"
"errors"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -129,7 +130,7 @@ func (s *SecureChannelSession) Pair(pairingPassword []byte) error {
// Unpair disestablishes an existing pairing. // Unpair disestablishes an existing pairing.
func (s *SecureChannelSession) Unpair() error { func (s *SecureChannelSession) Unpair() error {
if s.PairingKey == nil { if s.PairingKey == nil {
return fmt.Errorf("cannot unpair: not paired") return errors.New("cannot unpair: not paired")
} }
_, err := s.transmitEncrypted(claSCWallet, insUnpair, s.PairingIndex, 0, []byte{}) _, err := s.transmitEncrypted(claSCWallet, insUnpair, s.PairingIndex, 0, []byte{})
@ -147,7 +148,7 @@ func (s *SecureChannelSession) Unpair() error {
// Open initializes the secure channel. // Open initializes the secure channel.
func (s *SecureChannelSession) Open() error { func (s *SecureChannelSession) Open() error {
if s.iv != nil { if s.iv != nil {
return fmt.Errorf("session already opened") return errors.New("session already opened")
} }
response, err := s.open() response, err := s.open()
@ -222,7 +223,7 @@ func (s *SecureChannelSession) pair(p1 uint8, data []byte) (*responseAPDU, error
// transmitEncrypted sends an encrypted message, and decrypts and returns the response. // transmitEncrypted sends an encrypted message, and decrypts and returns the response.
func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []byte) (*responseAPDU, error) { func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []byte) (*responseAPDU, error) {
if s.iv == nil { if s.iv == nil {
return nil, fmt.Errorf("channel not open") return nil, errors.New("channel not open")
} }
data, err := s.encryptAPDU(data) data, err := s.encryptAPDU(data)
@ -264,7 +265,7 @@ func (s *SecureChannelSession) transmitEncrypted(cla, ins, p1, p2 byte, data []b
} }
if !bytes.Equal(s.iv, rmac) { if !bytes.Equal(s.iv, rmac) {
return nil, fmt.Errorf("invalid MAC in response") return nil, errors.New("invalid MAC in response")
} }
rapdu := &responseAPDU{} rapdu := &responseAPDU{}
@ -334,8 +335,7 @@ func unpad(data []byte, terminator byte) ([]byte, error) {
return nil, fmt.Errorf("expected end of padding, got %d", data[len(data)-i]) return nil, fmt.Errorf("expected end of padding, got %d", data[len(data)-i])
} }
} }
return nil, errors.New("expected end of padding, got 0")
return nil, fmt.Errorf("expected end of padding, got 0")
} }
// updateIV is an internal method that updates the initialization vector after // updateIV is an internal method that updates the initialization vector after

View file

@ -258,7 +258,7 @@ func (w *Wallet) release() error {
// with the wallet. // with the wallet.
func (w *Wallet) pair(puk []byte) error { func (w *Wallet) pair(puk []byte) error {
if w.session.paired() { if w.session.paired() {
return fmt.Errorf("wallet already paired") return errors.New("wallet already paired")
} }
pairing, err := w.session.pair(puk) pairing, err := w.session.pair(puk)
@ -850,7 +850,7 @@ func (s *Session) pair(secret []byte) (smartcardPairing, error) {
// unpair deletes an existing pairing. // unpair deletes an existing pairing.
func (s *Session) unpair() error { func (s *Session) unpair() error {
if !s.verified { if !s.verified {
return fmt.Errorf("unpair requires that the PIN be verified") return errors.New("unpair requires that the PIN be verified")
} }
return s.Channel.Unpair() return s.Channel.Unpair()
@ -955,7 +955,7 @@ func (s *Session) initialize(seed []byte) error {
} }
if status == "Online" { if status == "Online" {
return fmt.Errorf("card is already initialized, cowardly refusing to proceed") return errors.New("card is already initialized, cowardly refusing to proceed")
} }
s.Wallet.lock.Lock() s.Wallet.lock.Lock()

View file

@ -63,9 +63,9 @@ type Hub struct {
stateLock sync.RWMutex // Protects the internals of the hub from racey access stateLock sync.RWMutex // Protects the internals of the hub from racey access
// TODO(karalabe): remove if hotplug lands on Windows // TODO(karalabe): remove if hotplug lands on Windows
commsPend int // Number of operations blocking enumeration commsPend int // Number of operations blocking enumeration
commsLock sync.Mutex // Lock protecting the pending counter and enumeration commsLock sync.Mutex // Lock protecting the pending counter and enumeration
enumFails uint32 // Number of times enumeration has failed enumFails atomic.Uint32 // Number of times enumeration has failed
} }
// NewLedgerHub creates a new hardware wallet manager for Ledger devices. // NewLedgerHub creates a new hardware wallet manager for Ledger devices.
@ -154,7 +154,7 @@ func (hub *Hub) refreshWallets() {
return return
} }
// If USB enumeration is continually failing, don't keep trying indefinitely // If USB enumeration is continually failing, don't keep trying indefinitely
if atomic.LoadUint32(&hub.enumFails) > 2 { if hub.enumFails.Load() > 2 {
return return
} }
// Retrieve the current list of USB wallet devices // Retrieve the current list of USB wallet devices
@ -176,8 +176,7 @@ func (hub *Hub) refreshWallets() {
infos, err := usb.Enumerate(hub.vendorID, 0) infos, err := usb.Enumerate(hub.vendorID, 0)
if err != nil { if err != nil {
failcount := atomic.AddUint32(&hub.enumFails, 1) failcount := hub.enumFails.Add(1)
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {
// See rationale before the enumeration why this is needed and only on Linux. // See rationale before the enumeration why this is needed and only on Linux.
hub.commsLock.Unlock() hub.commsLock.Unlock()
@ -188,8 +187,7 @@ func (hub *Hub) refreshWallets() {
return return
} }
hub.enumFails.Store(0)
atomic.StoreUint32(&hub.enumFails, 0)
for _, info := range infos { for _, info := range infos {
for _, id := range hub.productIDs { for _, id := range hub.productIDs {

View file

@ -653,7 +653,7 @@ func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID
return signed, nil return signed, nil
} }
// SignHashWithPassphrase implements accounts.Wallet, however signing arbitrary // SignTextWithPassphrase implements accounts.Wallet, however signing arbitrary
// data is not supported for Ledger wallets, so this method will always return // data is not supported for Ledger wallets, so this method will always return
// an error. // an error.
func (w *wallet) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) { func (w *wallet) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) {

View file

@ -32,6 +32,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
BlockHash common.Hash `json:"blockHash" gencodec:"required"` BlockHash common.Hash `json:"blockHash" gencodec:"required"`
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
} }
var enc ExecutableData var enc ExecutableData
@ -57,7 +59,8 @@ func (e ExecutableData) MarshalJSON() ([]byte, error) {
} }
enc.Withdrawals = e.Withdrawals enc.Withdrawals = e.Withdrawals
enc.BlobGasUsed = (*hexutil.Uint64)(e.BlobGasUsed)
enc.ExcessBlobGas = (*hexutil.Uint64)(e.ExcessBlobGas)
return json.Marshal(&enc) return json.Marshal(&enc)
} }
@ -79,6 +82,8 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
BlockHash *common.Hash `json:"blockHash" gencodec:"required"` BlockHash *common.Hash `json:"blockHash" gencodec:"required"`
Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"` Transactions []hexutil.Bytes `json:"transactions" gencodec:"required"`
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"`
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"`
} }
var dec ExecutableData var dec ExecutableData
@ -176,6 +181,11 @@ func (e *ExecutableData) UnmarshalJSON(input []byte) error {
if dec.Withdrawals != nil { if dec.Withdrawals != nil {
e.Withdrawals = dec.Withdrawals e.Withdrawals = dec.Withdrawals
} }
if dec.BlobGasUsed != nil {
e.BlobGasUsed = (*uint64)(dec.BlobGasUsed)
}
if dec.ExcessBlobGas != nil {
e.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
}
return nil return nil
} }

View file

@ -17,12 +17,13 @@ func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) {
type ExecutionPayloadEnvelope struct { type ExecutionPayloadEnvelope struct {
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
} }
var enc ExecutionPayloadEnvelope var enc ExecutionPayloadEnvelope
enc.ExecutionPayload = e.ExecutionPayload enc.ExecutionPayload = e.ExecutionPayload
enc.BlockValue = (*hexutil.Big)(e.BlockValue) enc.BlockValue = (*hexutil.Big)(e.BlockValue)
enc.BlobsBundle = e.BlobsBundle
return json.Marshal(&enc) return json.Marshal(&enc)
} }
@ -31,6 +32,7 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
type ExecutionPayloadEnvelope struct { type ExecutionPayloadEnvelope struct {
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
} }
var dec ExecutionPayloadEnvelope var dec ExecutionPayloadEnvelope
@ -49,6 +51,8 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
} }
e.BlockValue = (*big.Int)(dec.BlockValue) e.BlockValue = (*big.Int)(dec.BlockValue)
if dec.BlobsBundle != nil {
e.BlobsBundle = dec.BlobsBundle
}
return nil return nil
} }

View file

@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
) )
@ -61,6 +62,8 @@ type ExecutableData struct {
BlockHash common.Hash `json:"blockHash" gencodec:"required"` BlockHash common.Hash `json:"blockHash" gencodec:"required"`
Transactions [][]byte `json:"transactions" gencodec:"required"` Transactions [][]byte `json:"transactions" gencodec:"required"`
Withdrawals []*types.Withdrawal `json:"withdrawals"` Withdrawals []*types.Withdrawal `json:"withdrawals"`
BlobGasUsed *uint64 `json:"blobGasUsed"`
ExcessBlobGas *uint64 `json:"excessBlobGas"`
} }
// JSON type overrides for executableData. // JSON type overrides for executableData.
@ -73,6 +76,8 @@ type executableDataMarshaling struct {
ExtraData hexutil.Bytes ExtraData hexutil.Bytes
LogsBloom hexutil.Bytes LogsBloom hexutil.Bytes
Transactions []hexutil.Bytes Transactions []hexutil.Bytes
BlobGasUsed *hexutil.Uint64
ExcessBlobGas *hexutil.Uint64
} }
//go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go //go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go
@ -80,6 +85,13 @@ type executableDataMarshaling struct {
type ExecutionPayloadEnvelope struct { type ExecutionPayloadEnvelope struct {
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
BlockValue *big.Int `json:"blockValue" gencodec:"required"` BlockValue *big.Int `json:"blockValue" gencodec:"required"`
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
}
type BlobsBundleV1 struct {
Commitments []hexutil.Bytes `json:"commitments"`
Proofs []hexutil.Bytes `json:"proofs"`
Blobs []hexutil.Bytes `json:"blobs"`
} }
// JSON type overrides for ExecutionPayloadEnvelope. // JSON type overrides for ExecutionPayloadEnvelope.
@ -157,14 +169,15 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
// ExecutableDataToBlock constructs a block from executable data. // ExecutableDataToBlock constructs a block from executable data.
// It verifies that the following fields: // It verifies that the following fields:
// //
// len(extraData) <= 32 // len(extraData) <= 32
// uncleHash = emptyUncleHash // uncleHash = emptyUncleHash
// difficulty = 0 // difficulty = 0
// if versionedHashes != nil, versionedHashes match to blob transactions
// //
// and that the blockhash of the constructed block matches the parameters. Nil // and that the blockhash of the constructed block matches the parameters. Nil
// Withdrawals value will propagate through the returned block. Empty // Withdrawals value will propagate through the returned block. Empty
// Withdrawals value must be passed via non-nil, length 0 value in params. // Withdrawals value must be passed via non-nil, length 0 value in params.
func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) { func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash) (*types.Block, error) {
txs, err := decodeTransactions(params.Transactions) txs, err := decodeTransactions(params.Transactions)
if err != nil { if err != nil {
return nil, err return nil, err
@ -181,6 +194,18 @@ func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) {
if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) { if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) {
return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas) return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas)
} }
var blobHashes []common.Hash
for _, tx := range txs {
blobHashes = append(blobHashes, tx.BlobHashes()...)
}
if len(blobHashes) != len(versionedHashes) {
return nil, fmt.Errorf("invalid number of versionedHashes: %v blobHashes: %v", versionedHashes, blobHashes)
}
for i := 0; i < len(blobHashes); i++ {
if blobHashes[i] != versionedHashes[i] {
return nil, fmt.Errorf("invalid versionedHash at %v: %v blobHashes: %v", i, versionedHashes, blobHashes)
}
}
// Only set withdrawalsRoot if it is non-nil. This allows CLs to use // Only set withdrawalsRoot if it is non-nil. This allows CLs to use
// ExecutableData before withdrawals are enabled by marshaling // ExecutableData before withdrawals are enabled by marshaling
// Withdrawals as the json null value. // Withdrawals as the json null value.
@ -208,6 +233,8 @@ func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) {
Extra: params.ExtraData, Extra: params.ExtraData,
MixDigest: params.Random, MixDigest: params.Random,
WithdrawalsHash: withdrawalsRoot, WithdrawalsHash: withdrawalsRoot,
ExcessBlobGas: params.ExcessBlobGas,
BlobGasUsed: params.BlobGasUsed,
} }
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals) block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals)
@ -220,7 +247,7 @@ func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) {
// BlockToExecutableData constructs the ExecutableData structure by filling the // BlockToExecutableData constructs the ExecutableData structure by filling the
// fields from the given block. It assumes the given block is post-merge block. // fields from the given block. It assumes the given block is post-merge block.
func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutionPayloadEnvelope { func BlockToExecutableData(block *types.Block, fees *big.Int, blobs []kzg4844.Blob, commitments []kzg4844.Commitment, proofs []kzg4844.Proof) *ExecutionPayloadEnvelope {
data := &ExecutableData{ data := &ExecutableData{
BlockHash: block.Hash(), BlockHash: block.Hash(),
ParentHash: block.ParentHash(), ParentHash: block.ParentHash(),
@ -237,9 +264,20 @@ func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutionPayloadE
Random: block.MixDigest(), Random: block.MixDigest(),
ExtraData: block.Extra(), ExtraData: block.Extra(),
Withdrawals: block.Withdrawals(), Withdrawals: block.Withdrawals(),
BlobGasUsed: block.BlobGasUsed(),
ExcessBlobGas: block.ExcessBlobGas(),
} }
blobsBundle := BlobsBundleV1{
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees} Commitments: make([]hexutil.Bytes, 0),
Blobs: make([]hexutil.Bytes, 0),
Proofs: make([]hexutil.Bytes, 0),
}
for i := range blobs {
blobsBundle.Blobs = append(blobsBundle.Blobs, hexutil.Bytes(blobs[i][:]))
blobsBundle.Commitments = append(blobsBundle.Commitments, hexutil.Bytes(commitments[i][:]))
blobsBundle.Proofs = append(blobsBundle.Proofs, hexutil.Bytes(proofs[i][:]))
}
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &blobsBundle}
} }
// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1 // ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1

67
beacon/merkle/merkle.go Normal file
View file

@ -0,0 +1,67 @@
// Copyright 2022 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 merkle implements proof verifications in binary merkle trees.
package merkle
import (
"crypto/sha256"
"errors"
"reflect"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
// Value represents either a 32 byte leaf value or hash node in a binary merkle tree/partial proof.
type Value [32]byte
// Values represent a series of merkle tree leaves/nodes.
type Values []Value
var valueT = reflect.TypeOf(Value{})
// UnmarshalJSON parses a merkle value in hex syntax.
func (m *Value) UnmarshalJSON(input []byte) error {
return hexutil.UnmarshalFixedJSON(valueT, input, m[:])
}
// VerifyProof verifies a Merkle proof branch for a single value in a
// binary Merkle tree (index is a generalized tree index).
func VerifyProof(root common.Hash, index uint64, branch Values, value Value) error {
hasher := sha256.New()
for _, sibling := range branch {
hasher.Reset()
if index&1 == 0 {
hasher.Write(value[:])
hasher.Write(sibling[:])
} else {
hasher.Write(sibling[:])
hasher.Write(value[:])
}
hasher.Sum(value[:0])
if index >>= 1; index == 0 {
return errors.New("branch has extra items")
}
}
if index != 1 {
return errors.New("branch is missing items")
}
if common.Hash(value) != root {
return errors.New("root mismatch")
}
return nil
}

View file

@ -1,4 +1,4 @@
// Copyright 2019 The go-ethereum Authors // Copyright 2022 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify
@ -14,23 +14,31 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package snapshot package params
import ( const (
"bytes" EpochLength = 32
SyncPeriodLength = 8192
"github.com/ethereum/go-ethereum/common" BLSSignatureSize = 96
BLSPubkeySize = 48
SyncCommitteeSize = 512
SyncCommitteeBitmaskSize = SyncCommitteeSize / 8
SyncCommitteeSupermajority = (SyncCommitteeSize*2 + 2) / 3
) )
// hashes is a helper to implement sort.Interface. const (
type hashes []common.Hash StateIndexGenesisTime = 32
StateIndexGenesisValidators = 33
// Len is the number of elements in the collection. StateIndexForkVersion = 141
func (hs hashes) Len() int { return len(hs) } StateIndexLatestHeader = 36
StateIndexBlockRoots = 37
// Less reports whether the element with index i should sort before the element StateIndexStateRoots = 38
// with index j. StateIndexHistoricRoots = 39
func (hs hashes) Less(i, j int) bool { return bytes.Compare(hs[i][:], hs[j][:]) < 0 } StateIndexFinalBlock = 105
StateIndexSyncCommittee = 54
// Swap swaps the elements with indexes i and j. StateIndexNextSyncCommittee = 55
func (hs hashes) Swap(i, j int) { hs[i], hs[j] = hs[j], hs[i] } StateIndexExecPayload = 56
StateIndexExecHead = 908
)

191
beacon/types/committee.go Normal file
View file

@ -0,0 +1,191 @@
// Copyright 2023 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 (
"crypto/sha256"
"encoding/json"
"fmt"
"math/bits"
"github.com/ethereum/go-ethereum/beacon/params"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
bls "github.com/protolambda/bls12-381-util"
)
// SerializedSyncCommitteeSize is the size of the sync committee plus the
// aggregate public key.
const SerializedSyncCommitteeSize = (params.SyncCommitteeSize + 1) * params.BLSPubkeySize
// SerializedSyncCommittee is the serialized version of a sync committee
// plus the aggregate public key.
type SerializedSyncCommittee [SerializedSyncCommitteeSize]byte
// jsonSyncCommittee is the JSON representation of a sync committee.
//
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate
type jsonSyncCommittee struct {
Pubkeys []hexutil.Bytes `json:"pubkeys"`
Aggregate hexutil.Bytes `json:"aggregate_pubkey"`
}
// MarshalJSON implements json.Marshaler.
func (s *SerializedSyncCommittee) MarshalJSON() ([]byte, error) {
sc := jsonSyncCommittee{Pubkeys: make([]hexutil.Bytes, params.SyncCommitteeSize)}
for i := range sc.Pubkeys {
sc.Pubkeys[i] = make(hexutil.Bytes, params.BLSPubkeySize)
copy(sc.Pubkeys[i][:], s[i*params.BLSPubkeySize:(i+1)*params.BLSPubkeySize])
}
sc.Aggregate = make(hexutil.Bytes, params.BLSPubkeySize)
copy(sc.Aggregate[:], s[params.SyncCommitteeSize*params.BLSPubkeySize:])
return json.Marshal(&sc)
}
// UnmarshalJSON implements json.Marshaler.
func (s *SerializedSyncCommittee) UnmarshalJSON(input []byte) error {
var sc jsonSyncCommittee
if err := json.Unmarshal(input, &sc); err != nil {
return err
}
if len(sc.Pubkeys) != params.SyncCommitteeSize {
return fmt.Errorf("invalid number of pubkeys %d", len(sc.Pubkeys))
}
for i, key := range sc.Pubkeys {
if len(key) != params.BLSPubkeySize {
return fmt.Errorf("pubkey %d has invalid size %d", i, len(key))
}
copy(s[i*params.BLSPubkeySize:], key[:])
}
if len(sc.Aggregate) != params.BLSPubkeySize {
return fmt.Errorf("invalid aggregate pubkey size %d", len(sc.Aggregate))
}
copy(s[params.SyncCommitteeSize*params.BLSPubkeySize:], sc.Aggregate[:])
return nil
}
// Root calculates the root hash of the binary tree representation of a sync
// committee provided in serialized format.
//
// TODO(zsfelfoldi): Get rid of this when SSZ encoding lands.
func (s *SerializedSyncCommittee) Root() common.Hash {
var (
hasher = sha256.New()
padding [64 - params.BLSPubkeySize]byte
data [params.SyncCommitteeSize]common.Hash
l = params.SyncCommitteeSize
)
for i := range data {
hasher.Reset()
hasher.Write(s[i*params.BLSPubkeySize : (i+1)*params.BLSPubkeySize])
hasher.Write(padding[:])
hasher.Sum(data[i][:0])
}
for l > 1 {
for i := 0; i < l/2; i++ {
hasher.Reset()
hasher.Write(data[i*2][:])
hasher.Write(data[i*2+1][:])
hasher.Sum(data[i][:0])
}
l /= 2
}
hasher.Reset()
hasher.Write(s[SerializedSyncCommitteeSize-params.BLSPubkeySize : SerializedSyncCommitteeSize])
hasher.Write(padding[:])
hasher.Sum(data[1][:0])
hasher.Reset()
hasher.Write(data[0][:])
hasher.Write(data[1][:])
hasher.Sum(data[0][:0])
return data[0]
}
// Deserialize splits open the pubkeys into proper BLS key types.
func (s *SerializedSyncCommittee) Deserialize() (*SyncCommittee, error) {
sc := new(SyncCommittee)
for i := 0; i <= params.SyncCommitteeSize; i++ {
key := new(bls.Pubkey)
var bytes [params.BLSPubkeySize]byte
copy(bytes[:], s[i*params.BLSPubkeySize:(i+1)*params.BLSPubkeySize])
if err := key.Deserialize(&bytes); err != nil {
return nil, err
}
if i < params.SyncCommitteeSize {
sc.keys[i] = key
} else {
sc.aggregate = key
}
}
return sc, nil
}
// SyncCommittee is a set of sync committee signer pubkeys and the aggregate key.
//
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate
type SyncCommittee struct {
keys [params.SyncCommitteeSize]*bls.Pubkey
aggregate *bls.Pubkey
}
// VerifySignature returns true if the given sync aggregate is a valid signature
// or the given hash.
func (sc *SyncCommittee) VerifySignature(signingRoot common.Hash, signature *SyncAggregate) bool {
var (
sig bls.Signature
keys = make([]*bls.Pubkey, 0, params.SyncCommitteeSize)
)
if err := sig.Deserialize(&signature.Signature); err != nil {
return false
}
for i, key := range sc.keys {
if signature.Signers[i/8]&(byte(1)<<(i%8)) != 0 {
keys = append(keys, key)
}
}
return bls.FastAggregateVerify(keys, signingRoot[:], &sig)
}
//go:generate go run github.com/fjl/gencodec -type SyncAggregate -field-override syncAggregateMarshaling -out gen_syncaggregate_json.go
// SyncAggregate represents an aggregated BLS signature with Signers referring
// to a subset of the corresponding sync committee.
//
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#syncaggregate
type SyncAggregate struct {
Signers [params.SyncCommitteeBitmaskSize]byte `gencodec:"required" json:"sync_committee_bits"`
Signature [params.BLSSignatureSize]byte `gencodec:"required" json:"sync_committee_signature"`
}
type syncAggregateMarshaling struct {
Signers hexutil.Bytes
Signature hexutil.Bytes
}
// SignerCount returns the number of signers in the aggregate signature.
func (s *SyncAggregate) SignerCount() int {
var count int
for _, v := range s.Signers {
count += bits.OnesCount8(v)
}
return count
}

176
beacon/types/config.go Normal file
View file

@ -0,0 +1,176 @@
// Copyright 2022 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 (
"crypto/sha256"
"fmt"
"os"
"sort"
"strconv"
"strings"
"github.com/ethereum/go-ethereum/beacon/merkle"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"gopkg.in/yaml.v3"
)
// syncCommitteeDomain specifies the signatures specific use to avoid clashes
// across signing different data structures.
const syncCommitteeDomain = 7
// Fork describes a single beacon chain fork and also stores the calculated
// signature domain used after this fork.
type Fork struct {
// Name of the fork in the chain config (config.yaml) file{
Name string
// Epoch when given fork version is activated
Epoch uint64
// Fork version, see https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types
Version []byte
// calculated by computeDomain, based on fork version and genesis validators root
domain merkle.Value
}
// computeDomain returns the signature domain based on the given fork version
// and genesis validator set root.
func (f *Fork) computeDomain(genesisValidatorsRoot common.Hash) {
var (
hasher = sha256.New()
forkVersion32 merkle.Value
forkDataRoot merkle.Value
)
copy(forkVersion32[:], f.Version)
hasher.Write(forkVersion32[:])
hasher.Write(genesisValidatorsRoot[:])
hasher.Sum(forkDataRoot[:0])
f.domain[0] = syncCommitteeDomain
copy(f.domain[4:], forkDataRoot[:28])
}
// Forks is the list of all beacon chain forks in the chain configuration.
type Forks []*Fork
// domain returns the signature domain for the given epoch (assumes that domains
// have already been calculated).
func (f Forks) domain(epoch uint64) (merkle.Value, error) {
for i := len(f) - 1; i >= 0; i-- {
if epoch >= f[i].Epoch {
return f[i].domain, nil
}
}
return merkle.Value{}, fmt.Errorf("unknown fork for epoch %d", epoch)
}
// SigningRoot calculates the signing root of the given header.
func (f Forks) SigningRoot(header Header) (common.Hash, error) {
domain, err := f.domain(header.Epoch())
if err != nil {
return common.Hash{}, err
}
var (
signingRoot common.Hash
headerHash = header.Hash()
hasher = sha256.New()
)
hasher.Write(headerHash[:])
hasher.Write(domain[:])
hasher.Sum(signingRoot[:0])
return signingRoot, nil
}
func (f Forks) Len() int { return len(f) }
func (f Forks) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
func (f Forks) Less(i, j int) bool { return f[i].Epoch < f[j].Epoch }
// ChainConfig contains the beacon chain configuration.
type ChainConfig struct {
GenesisTime uint64 // Unix timestamp of slot 0
GenesisValidatorsRoot common.Hash // Root hash of the genesis validator set, used for signature domain calculation
Forks Forks
}
// AddFork adds a new item to the list of forks.
func (c *ChainConfig) AddFork(name string, epoch uint64, version []byte) *ChainConfig {
fork := &Fork{
Name: name,
Epoch: epoch,
Version: version,
}
fork.computeDomain(c.GenesisValidatorsRoot)
c.Forks = append(c.Forks, fork)
sort.Sort(c.Forks)
return c
}
// LoadForks parses the beacon chain configuration file (config.yaml) and extracts
// the list of forks.
func (c *ChainConfig) LoadForks(path string) error {
file, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("failed to read beacon chain config file: %v", err)
}
config := make(map[string]string)
if err := yaml.Unmarshal(file, &config); err != nil {
return fmt.Errorf("failed to parse beacon chain config file: %v", err)
}
var (
versions = make(map[string][]byte)
epochs = make(map[string]uint64)
)
epochs["GENESIS"] = 0
for key, value := range config {
if strings.HasSuffix(key, "_FORK_VERSION") {
name := key[:len(key)-len("_FORK_VERSION")]
if v, err := hexutil.Decode(value); err == nil {
versions[name] = v
} else {
return fmt.Errorf("failed to decode hex fork id %q in beacon chain config file: %v", value, err)
}
}
if strings.HasSuffix(key, "_FORK_EPOCH") {
name := key[:len(key)-len("_FORK_EPOCH")]
if v, err := strconv.ParseUint(value, 10, 64); err == nil {
epochs[name] = v
} else {
return fmt.Errorf("failed to parse epoch number %q in beacon chain config file: %v", value, err)
}
}
}
for name, epoch := range epochs {
if version, ok := versions[name]; ok {
delete(versions, name)
c.AddFork(name, epoch, version)
} else {
return fmt.Errorf("fork id missing for %q in beacon chain config file", name)
}
}
for name := range versions {
return fmt.Errorf("epoch number missing for fork %q in beacon chain config file", name)
}
sort.Sort(c.Forks)
return nil
}

View file

@ -0,0 +1,66 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package types
import (
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/common"
)
var _ = (*headerMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (h Header) MarshalJSON() ([]byte, error) {
type Header struct {
Slot common.Decimal `gencodec:"required" json:"slot"`
ProposerIndex common.Decimal `gencodec:"required" json:"proposer_index"`
ParentRoot common.Hash `gencodec:"required" json:"parent_root"`
StateRoot common.Hash `gencodec:"required" json:"state_root"`
BodyRoot common.Hash `gencodec:"required" json:"body_root"`
}
var enc Header
enc.Slot = common.Decimal(h.Slot)
enc.ProposerIndex = common.Decimal(h.ProposerIndex)
enc.ParentRoot = h.ParentRoot
enc.StateRoot = h.StateRoot
enc.BodyRoot = h.BodyRoot
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (h *Header) UnmarshalJSON(input []byte) error {
type Header struct {
Slot *common.Decimal `gencodec:"required" json:"slot"`
ProposerIndex *common.Decimal `gencodec:"required" json:"proposer_index"`
ParentRoot *common.Hash `gencodec:"required" json:"parent_root"`
StateRoot *common.Hash `gencodec:"required" json:"state_root"`
BodyRoot *common.Hash `gencodec:"required" json:"body_root"`
}
var dec Header
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Slot == nil {
return errors.New("missing required field 'slot' for Header")
}
h.Slot = uint64(*dec.Slot)
if dec.ProposerIndex == nil {
return errors.New("missing required field 'proposer_index' for Header")
}
h.ProposerIndex = uint64(*dec.ProposerIndex)
if dec.ParentRoot == nil {
return errors.New("missing required field 'parent_root' for Header")
}
h.ParentRoot = *dec.ParentRoot
if dec.StateRoot == nil {
return errors.New("missing required field 'state_root' for Header")
}
h.StateRoot = *dec.StateRoot
if dec.BodyRoot == nil {
return errors.New("missing required field 'body_root' for Header")
}
h.BodyRoot = *dec.BodyRoot
return nil
}

View file

@ -0,0 +1,51 @@
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
package types
import (
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/common/hexutil"
)
var _ = (*syncAggregateMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (s SyncAggregate) MarshalJSON() ([]byte, error) {
type SyncAggregate struct {
Signers hexutil.Bytes `gencodec:"required" json:"sync_committee_bits"`
Signature hexutil.Bytes `gencodec:"required" json:"sync_committee_signature"`
}
var enc SyncAggregate
enc.Signers = s.Signers[:]
enc.Signature = s.Signature[:]
return json.Marshal(&enc)
}
// UnmarshalJSON unmarshals from JSON.
func (s *SyncAggregate) UnmarshalJSON(input []byte) error {
type SyncAggregate struct {
Signers *hexutil.Bytes `gencodec:"required" json:"sync_committee_bits"`
Signature *hexutil.Bytes `gencodec:"required" json:"sync_committee_signature"`
}
var dec SyncAggregate
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Signers == nil {
return errors.New("missing required field 'sync_committee_bits' for SyncAggregate")
}
if len(*dec.Signers) != len(s.Signers) {
return errors.New("field 'sync_committee_bits' has wrong length, need 64 items")
}
copy(s.Signers[:], *dec.Signers)
if dec.Signature == nil {
return errors.New("missing required field 'sync_committee_signature' for SyncAggregate")
}
if len(*dec.Signature) != len(s.Signature) {
return errors.New("field 'sync_committee_signature' has wrong length, need 96 items")
}
copy(s.Signature[:], *dec.Signature)
return nil
}

121
beacon/types/header.go Normal file
View file

@ -0,0 +1,121 @@
// Copyright 2022 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 implements a few types of the beacon chain for light client usage.
package types
import (
"crypto/sha256"
"encoding/binary"
"github.com/ethereum/go-ethereum/beacon/merkle"
"github.com/ethereum/go-ethereum/beacon/params"
"github.com/ethereum/go-ethereum/common"
)
//go:generate go run github.com/fjl/gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
const (
headerIndexSlot = 8
headerIndexProposerIndex = 9
headerIndexParentRoot = 10
headerIndexStateRoot = 11
headerIndexBodyRoot = 12
)
// Header defines a beacon header.
//
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader
type Header struct {
// Monotonically increasing slot number for the beacon block (may be gapped)
Slot uint64 `gencodec:"required" json:"slot"`
// Index into the validator table who created the beacon block
ProposerIndex uint64 `gencodec:"required" json:"proposer_index"`
// SSZ hash of the parent beacon header
ParentRoot common.Hash `gencodec:"required" json:"parent_root"`
// SSZ hash of the beacon state (https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#beacon-state)
StateRoot common.Hash `gencodec:"required" json:"state_root"`
// SSZ hash of the beacon block body (https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#beaconblockbody)
BodyRoot common.Hash `gencodec:"required" json:"body_root"`
}
// headerMarshaling is a field type overrides for gencodec.
type headerMarshaling struct {
Slot common.Decimal
ProposerIndex common.Decimal
}
// Hash calculates the block root of the header.
//
// TODO(zsfelfoldi): Remove this when an SSZ encoder lands.
func (h *Header) Hash() common.Hash {
var values [16]merkle.Value // values corresponding to indices 8 to 15 of the beacon header tree
binary.LittleEndian.PutUint64(values[headerIndexSlot][:8], h.Slot)
binary.LittleEndian.PutUint64(values[headerIndexProposerIndex][:8], h.ProposerIndex)
values[headerIndexParentRoot] = merkle.Value(h.ParentRoot)
values[headerIndexStateRoot] = merkle.Value(h.StateRoot)
values[headerIndexBodyRoot] = merkle.Value(h.BodyRoot)
hasher := sha256.New()
for i := 7; i > 0; i-- {
hasher.Reset()
hasher.Write(values[i*2][:])
hasher.Write(values[i*2+1][:])
hasher.Sum(values[i][:0])
}
return common.Hash(values[1])
}
// Epoch returns the epoch the header belongs to.
func (h *Header) Epoch() uint64 {
return h.Slot / params.EpochLength
}
// SyncPeriod returns the sync period the header belongs to.
func (h *Header) SyncPeriod() uint64 {
return SyncPeriod(h.Slot)
}
// SyncPeriodStart returns the first slot of the given period.
func SyncPeriodStart(period uint64) uint64 {
return period * params.SyncPeriodLength
}
// SyncPeriod returns the sync period that the given slot belongs to.
func SyncPeriod(slot uint64) uint64 {
return slot / params.SyncPeriodLength
}
// SignedHeader represents a beacon header signed by a sync committee.
//
// This structure is created from either an optimistic update or an instant update:
// - https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientoptimisticupdate
// - https://github.com/zsfelfoldi/beacon-APIs/blob/instant_update/apis/beacon/light_client/instant_update.yaml
type SignedHeader struct {
// Beacon header being signed
Header Header
// Sync committee BLS signature aggregate
Signature SyncAggregate
// Slot in which the signature has been created (newer than Header.Slot,
// determines the signing sync committee)
SignatureSlot uint64
}

118
beacon/types/update.go Normal file
View file

@ -0,0 +1,118 @@
// Copyright 2022 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 (
"errors"
"fmt"
"github.com/ethereum/go-ethereum/beacon/merkle"
"github.com/ethereum/go-ethereum/beacon/params"
"github.com/ethereum/go-ethereum/common"
)
// LightClientUpdate is a proof of the next sync committee root based on a header
// signed by the sync committee of the given period. Optionally, the update can
// prove quasi-finality by the signed header referring to a previous, finalized
// header from the same period, and the finalized header referring to the next
// sync committee root.
//
// See data structure definition here:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md#lightclientupdate
type LightClientUpdate struct {
AttestedHeader SignedHeader // Arbitrary header out of the period signed by the sync committee
NextSyncCommitteeRoot common.Hash // Sync committee of the next period advertised in the current one
NextSyncCommitteeBranch merkle.Values // Proof for the next period's sync committee
FinalizedHeader *Header `rlp:"nil"` // Optional header to announce a point of finality
FinalityBranch merkle.Values // Proof for the announced finality
score *UpdateScore // Weight of the update to compare between competing ones
}
// Validate verifies the validity of the update.
func (update *LightClientUpdate) Validate() error {
period := update.AttestedHeader.Header.SyncPeriod()
if SyncPeriod(update.AttestedHeader.SignatureSlot) != period {
return errors.New("signature slot and signed header are from different periods")
}
if update.FinalizedHeader != nil {
if update.FinalizedHeader.SyncPeriod() != period {
return errors.New("finalized header is from different period")
}
if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexFinalBlock, update.FinalityBranch, merkle.Value(update.FinalizedHeader.Hash())); err != nil {
return fmt.Errorf("invalid finalized header proof: %w", err)
}
}
if err := merkle.VerifyProof(update.AttestedHeader.Header.StateRoot, params.StateIndexNextSyncCommittee, update.NextSyncCommitteeBranch, merkle.Value(update.NextSyncCommitteeRoot)); err != nil {
return fmt.Errorf("invalid next sync committee proof: %w", err)
}
return nil
}
// Score returns the UpdateScore describing the proof strength of the update
// Note: thread safety can be ensured by always calling Score on a newly received
// or decoded update before making it potentially available for other threads
func (update *LightClientUpdate) Score() UpdateScore {
if update.score == nil {
update.score = &UpdateScore{
SignerCount: uint32(update.AttestedHeader.Signature.SignerCount()),
SubPeriodIndex: uint32(update.AttestedHeader.Header.Slot & 0x1fff),
FinalizedHeader: update.FinalizedHeader != nil,
}
}
return *update.score
}
// UpdateScore allows the comparison between updates at the same period in order
// to find the best update chain that provides the strongest proof of being canonical.
//
// UpdateScores have a tightly packed binary encoding format for efficient p2p
// protocol transmission. Each UpdateScore is encoded in 3 bytes.
// When interpreted as a 24 bit little indian unsigned integer:
// - the lowest 10 bits contain the number of signers in the header signature aggregate
// - the next 13 bits contain the "sub-period index" which is he signed header's
// slot modulo params.SyncPeriodLength (which is correlated with the risk of the chain being
// re-orged before the previous period boundary in case of non-finalized updates)
// - the highest bit is set when the update is finalized (meaning that the finality
// header referenced by the signed header is in the same period as the signed
// header, making reorgs before the period boundary impossible
type UpdateScore struct {
SignerCount uint32 // number of signers in the header signature aggregate
SubPeriodIndex uint32 // signed header's slot modulo params.SyncPeriodLength
FinalizedHeader bool // update is considered finalized if has finalized header from the same period and 2/3 signatures
}
// finalized returns true if the update has a header signed by at least 2/3 of
// the committee, referring to a finalized header that refers to the next sync
// committee. This condition is a close approximation of the actual finality
// condition that can only be verified by full beacon nodes.
func (u *UpdateScore) finalized() bool {
return u.FinalizedHeader && u.SignerCount >= params.SyncCommitteeSupermajority
}
// BetterThan returns true if update u is considered better than w.
func (u UpdateScore) BetterThan(w UpdateScore) bool {
var (
uFinalized = u.finalized()
wFinalized = w.finalized()
)
if uFinalized != wFinalized {
return uFinalized
}
return u.SignerCount > w.SignerCount
}

View file

@ -1,19 +1,19 @@
# This file contains sha256 checksums of optional build dependencies. # This file contains sha256 checksums of optional build dependencies.
38f423db4cc834883f2b52344282fa7a39fbb93650dc62a11fdf0be6409bdad6 go1.18.src.tar.gz 2c5ee9c9ec1e733b0dbbc2bdfed3f62306e51d8172bf38f4f4e542b27520f597 go1.20.7.src.tar.gz
70bb4a066997535e346c8bfa3e0dfe250d61100b17ccc5676274642447834969 go1.18.darwin-amd64.tar.gz 785170eab380a8985d53896808b0a71336d0ea60e0a26099b4ccec77798b1cf4 go1.20.7.darwin-amd64.tar.gz
9cab6123af9ffade905525d79fc9ee76651e716c85f1f215872b5f2976782480 go1.18.darwin-arm64.tar.gz eea1e7e4c2f75c72629050e6a6c7c46c446d64056732a7787fb3ba16ace1982e go1.20.7.darwin-arm64.tar.gz
e63492d4f38487331518eb4b50e670d853bb8d67e88596269af84bb9aca0b381 go1.18.freebsd-386.tar.gz d8cff0357ac24eb06f3f280535397eeaacf95611d29f9b2abc3060f3d6dce3b4 go1.20.7.freebsd-386.tar.gz
01cd67bbc12e659ff236ecebde1806f76452f7ca145c172d5ecdbf4f4803daae go1.18.freebsd-amd64.tar.gz 26918dcebf474a9e81ccf9f648cdf36968dfb76b481518cf615d78455dda4416 go1.20.7.freebsd-amd64.tar.gz
1c04cf4440b323a66328e0df95d409f955b9b475e58eae235fdd3d1f1cf02f4f go1.18.linux-386.tar.gz ddb48145f05bda2f4617a22c979d4e94b22802cdb1a1fde1b1974e733b26f091 go1.20.7.linux-386.tar.gz
e85278e98f57cdb150fe8409e6e5df5343ecb13cebf03a5d5ff12bd55a80264f go1.18.linux-amd64.tar.gz f0a87f1bcae91c4b69f8dc2bc6d7e6bfcd7524fceec130af525058c0c17b1b44 go1.20.7.linux-amd64.tar.gz
7ac7b396a691e588c5fb57687759e6c4db84a2a3bbebb0765f4b38e5b1c5b00e go1.18.linux-arm64.tar.gz 44781ae3b153c3b07651d93b6bc554e835a36e2d72a696281c1e4dad9efffe43 go1.20.7.linux-arm64.tar.gz
a80fa43d1f4575fb030adbfbaa94acd860c6847820764eecb06c63b7c103612b go1.18.linux-armv6l.tar.gz 7cc231b415b94f2f7065870a73f67dd2b0ec12b5a98052b7ee0121c42bc04f8d go1.20.7.linux-armv6l.tar.gz
070351edac192483c074b38d08ec19251a83f8210765a532a84c3dcf8aec04d8 go1.18.linux-ppc64le.tar.gz 6318a1db307c12b8afe68808bd6fae4fba1e558a85b958216096869ed506dcb3 go1.20.7.linux-ppc64le.tar.gz
ea265f5e62fcaf941d53f0cdb81222d9668e1672a0d39d992f16ff0e87c0ee6b go1.18.linux-s390x.tar.gz 26aea2ede8722ceecbd9db883328a8d963136fd96c11dacc356c44c4c19c6515 go1.20.7.linux-s390x.tar.gz
e23fd2a0509690fe7e63b2b1bcd4c39ed57b46ccde76f35dc0d16ca7fdbc5aaa go1.18.windows-386.zip 5b0ef6f58d3e04d6cc003aa98e9172f41ba9e091b1c98e7339b41c4c87fb78a1 go1.20.7.windows-386.zip
65c5c0c709a7ca1b357091b10b795b439d8b50e579d3893edab4c7e9b384f435 go1.18.windows-amd64.zip 736dc6c7fcab1c96b682c8c93e38d7e371e62a17d34cb2c37d451a1147f66af9 go1.20.7.windows-amd64.zip
1c454eb60c64d481965a165c623ff1ed6cf32d68c6b31f36069c8768d908f093 go1.18.windows-arm64.zip fc6f79c1e1ed9e506c65f2112ac4e387479916f1accb0d046a6a19ff6938baa5 go1.20.7.windows-arm64.zip
03c181fc1bb29ea3e73cbb23399c43b081063833a7cf7554b94e5a98308df53e golangci-lint-1.45.2-linux-riscv64.deb 03c181fc1bb29ea3e73cbb23399c43b081063833a7cf7554b94e5a98308df53e golangci-lint-1.45.2-linux-riscv64.deb
08a50bbbf451ede6d5354179eb3e14a5634e156dfa92cb9a2606f855a637e35b golangci-lint-1.45.2-linux-ppc64le.rpm 08a50bbbf451ede6d5354179eb3e14a5634e156dfa92cb9a2606f855a637e35b golangci-lint-1.45.2-linux-ppc64le.rpm

View file

@ -139,7 +139,15 @@ var (
// This is the version of Go that will be downloaded by // This is the version of Go that will be downloaded by
// //
// go run ci.go install -dlgo // go run ci.go install -dlgo
dlgoVersion = "1.20" dlgoVersion = "1.20.7"
// This is the version of Go that will be used to bootstrap the PPA builder.
//
// This version is fine to be old and full of security holes, we just use it
// to build the latest Go. Don't change it. If it ever becomes insufficient,
// we need to switch over to a recursive builder to jumpt across supported
// versions.
gobootVersion = "1.19.6"
) )
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin")) var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
@ -192,6 +200,7 @@ func doInstall(cmdline []string) {
staticlink = flag.Bool("static", false, "Create statically-linked executable") staticlink = flag.Bool("static", false, "Create statically-linked executable")
) )
flag.CommandLine.Parse(cmdline) flag.CommandLine.Parse(cmdline)
env := build.Env()
// Configure the toolchain. // Configure the toolchain.
tc := build.GoToolchain{GOARCH: *arch, CC: *cc} tc := build.GoToolchain{GOARCH: *arch, CC: *cc}
@ -203,8 +212,12 @@ func doInstall(cmdline []string) {
// Disable CLI markdown doc generation in release builds. // Disable CLI markdown doc generation in release builds.
buildTags := []string{"urfave_cli_no_docs"} buildTags := []string{"urfave_cli_no_docs"}
// Enable linking the CKZG library since we can make it work with additional flags.
if env.UbuntuVersion != "trusty" {
buildTags = append(buildTags, "ckzg")
}
// Configure the build. // Configure the build.
env := build.Env()
gobuild := tc.Go("build", buildFlags(env, *staticlink, buildTags)...) gobuild := tc.Go("build", buildFlags(env, *staticlink, buildTags)...)
// arm64 CI builders are memory-constrained and can't handle concurrent builds, // arm64 CI builders are memory-constrained and can't handle concurrent builds,
@ -213,7 +226,6 @@ func doInstall(cmdline []string) {
if env.CI && runtime.GOARCH == "arm64" { if env.CI && runtime.GOARCH == "arm64" {
gobuild.Args = append(gobuild.Args, "-p", "1") gobuild.Args = append(gobuild.Args, "-p", "1")
} }
// We use -trimpath to avoid leaking local paths into the built executables. // We use -trimpath to avoid leaking local paths into the built executables.
gobuild.Args = append(gobuild.Args, "-trimpath") gobuild.Args = append(gobuild.Args, "-trimpath")
@ -293,6 +305,12 @@ func doTest(cmdline []string) {
} }
gotest := tc.Go("test") gotest := tc.Go("test")
// CI needs a bit more time for the statetests (default 10m).
gotest.Args = append(gotest.Args, "-timeout=20m")
// Enable CKZG backend in CI.
gotest.Args = append(gotest.Args, "-tags=ckzg")
// Test a single package at a time. CI builders are slow // Test a single package at a time. CI builders are slow
// and some tests run into timeouts under load. // and some tests run into timeouts under load.
gotest.Args = append(gotest.Args, "-p", "1") gotest.Args = append(gotest.Args, "-p", "1")

View file

@ -28,7 +28,7 @@ override_dh_auto_build:
mv .mod $(GOPATH)/pkg/mod mv .mod $(GOPATH)/pkg/mod
# A fresh Go was built, all dependency downloads faked, hope build works now # A fresh Go was built, all dependency downloads faked, hope build works now
../.go/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}} ../.go/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}} -ubuntu {{.Distro}}
override_dh_auto_test: override_dh_auto_test:

View file

@ -46,12 +46,13 @@ import (
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime" "runtime"
"sort"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"text/template" "text/template"
"time" "time"
"golang.org/x/exp/slices"
) )
var ( var (
@ -152,13 +153,6 @@ func (i info) gpl() bool {
return false return false
} }
// authors implements the sort.Interface for strings in case-insensitive mode.
type authors []string
func (as authors) Len() int { return len(as) }
func (as authors) Less(i, j int) bool { return strings.ToLower(as[i]) < strings.ToLower(as[j]) }
func (as authors) Swap(i, j int) { as[i], as[j] = as[j], as[i] }
func main() { func main() {
var ( var (
files = getFiles() files = getFiles()
@ -299,7 +293,9 @@ func writeAuthors(files []string) {
} }
} }
// Write sorted list of authors back to the file. // Write sorted list of authors back to the file.
sort.Sort(authors(list)) slices.SortFunc(list, func(a, b string) bool {
return strings.ToLower(a) < strings.ToLower(b)
})
content := new(bytes.Buffer) content := new(bytes.Buffer)
content.WriteString(authorsFileHeader) content.WriteString(authorsFileHeader)
for _, a := range list { for _, a := range list {

View file

@ -23,6 +23,7 @@ import (
"fmt" "fmt"
"net" "net"
"os" "os"
"time"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -112,22 +113,20 @@ func main() {
if err != nil { if err != nil {
utils.Fatalf("-ListenUDP: %v", err) utils.Fatalf("-ListenUDP: %v", err)
} }
defer conn.Close()
realaddr := conn.LocalAddr().(*net.UDPAddr)
if natm != nil {
if !realaddr.IP.IsLoopback() {
go nat.Map(natm, nil, "udp", realaddr.Port, realaddr.Port, "ethereum discovery")
}
if ext, err := natm.ExternalIP(); err == nil {
realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port}
}
}
printNotice(&nodeKey.PublicKey, *realaddr)
db, _ := enode.OpenDB("") db, _ := enode.OpenDB("")
ln := enode.NewLocalNode(db, nodeKey) ln := enode.NewLocalNode(db, nodeKey)
listenerAddr := conn.LocalAddr().(*net.UDPAddr)
if natm != nil && !listenerAddr.IP.IsLoopback() {
natAddr := doPortMapping(natm, ln, listenerAddr)
if natAddr != nil {
listenerAddr = natAddr
}
}
printNotice(&nodeKey.PublicKey, *listenerAddr)
cfg := discover.Config{ cfg := discover.Config{
PrivateKey: nodeKey, PrivateKey: nodeKey,
NetRestrict: restrictList, NetRestrict: restrictList,
@ -156,3 +155,61 @@ func printNotice(nodeKey *ecdsa.PublicKey, addr net.UDPAddr) {
fmt.Println("Note: you're using cmd/bootnode, a developer tool.") fmt.Println("Note: you're using cmd/bootnode, a developer tool.")
fmt.Println("We recommend using a regular node as bootstrap node for production deployments.") fmt.Println("We recommend using a regular node as bootstrap node for production deployments.")
} }
func doPortMapping(natm nat.Interface, ln *enode.LocalNode, addr *net.UDPAddr) *net.UDPAddr {
const (
protocol = "udp"
name = "ethereum discovery"
)
newLogger := func(external int, internal int) log.Logger {
return log.New("proto", protocol, "extport", external, "intport", internal, "interface", natm)
}
var (
intport = addr.Port
extaddr = &net.UDPAddr{IP: addr.IP, Port: addr.Port}
mapTimeout = nat.DefaultMapTimeout
log = newLogger(addr.Port, intport)
)
addMapping := func() {
// Get the external address.
var err error
extaddr.IP, err = natm.ExternalIP()
if err != nil {
log.Debug("Couldn't get external IP", "err", err)
return
}
// Create the mapping.
p, err := natm.AddMapping(protocol, extaddr.Port, intport, name, mapTimeout)
if err != nil {
log.Debug("Couldn't add port mapping", "err", err)
return
}
if p != uint16(extaddr.Port) {
extaddr.Port = int(p)
log = newLogger(extaddr.Port, intport)
log.Info("NAT mapped alternative port")
} else {
log.Info("NAT mapped port")
}
// Update IP/port information of the local node.
ln.SetStaticIP(extaddr.IP)
ln.SetFallbackUDP(extaddr.Port)
}
// Perform mapping once, synchronously.
log.Info("Attempting port mapping")
addMapping()
// Refresh the mapping periodically.
go func() {
refresh := time.NewTimer(mapTimeout)
defer refresh.Stop()
for range refresh.C {
addMapping()
refresh.Reset(mapTimeout)
}
}()
return extaddr
}

View file

@ -1,103 +0,0 @@
## Checkpoint-admin
Checkpoint-admin is a tool for updating checkpoint oracle status. It provides a series of functions including deploying checkpoint oracle contract, signing for new checkpoints, and updating checkpoints in the checkpoint oracle contract.
### Checkpoint
In the LES protocol, there is an important concept called checkpoint. In simple terms, whenever a certain number of blocks are generated on the blockchain, a new checkpoint is generated which contains some important information such as
* Block hash at checkpoint
* Canonical hash trie root at checkpoint
* Bloom trie root at checkpoint
*For a more detailed introduction to checkpoint, please see the LES [spec](https://github.com/ethereum/devp2p/blob/master/caps/les.md).*
Using this information, light clients can skip all historical block headers when synchronizing data and start synchronization from this checkpoint. Therefore, as long as the light client can obtain some latest and correct checkpoints, the amount of data and time for synchronization will be greatly reduced.
However, from a security perspective, the most critical step in a synchronization algorithm based on checkpoints is to determine whether the checkpoint used by the light client is correct. Otherwise, all blockchain data synchronized based on this checkpoint may be wrong. For this we provide two different ways to ensure the correctness of the checkpoint used by the light client.
#### Hardcoded checkpoint
There are several hardcoded checkpoints in the [source code](https://github.com/ethereum/go-ethereum/blob/master/params/config.go#L38) of the go-ethereum project. These checkpoints are updated by go-ethereum developers when new versions of software are released. Because light client users trust Geth developers to some extent, hardcoded checkpoints in the code can also be considered correct.
#### Checkpoint oracle
Hardcoded checkpoints can solve the problem of verifying the correctness of checkpoints (although this is a more centralized solution). But the pain point of this solution is that developers can only update checkpoints when a new version of software is released. In addition, light client users usually do not keep the Geth version they use always up to date. So hardcoded checkpoints used by users are generally stale. Therefore, it still needs to download a large amount of blockchain data during synchronization.
Checkpoint oracle is a more flexible solution. In simple terms, this is a smart contract that is deployed on the blockchain. The smart contract records several designated trusted signers. Whenever enough trusted signers have issued their signatures for the same checkpoint, it can be considered that the checkpoint has been authenticated by the signers. Checkpoints authenticated by trusted signers can be considered correct.
So this way, even without updating the software version, as long as the trusted signers regularly update the checkpoint in oracle on time, the light client can always use the latest and verified checkpoint for data synchronization.
### Usage
Checkpoint-admin is a command line tool designed for checkpoint oracle. Users can easily deploy contracts and update checkpoints through this tool.
#### Install
```shell
go get github.com/ethereum/go-ethereum/cmd/checkpoint-admin
```
#### Deploy
Deploy checkpoint oracle contract. `--signers` indicates the specified trusted signer, and `--threshold` indicates the minimum number of signatures required by trusted signers to update a checkpoint.
```shell
checkpoint-admin deploy --rpc <NODE_RPC_ENDPOINT> --clef <CLEF_ENDPOINT> --signer <SIGNER_TO_SIGN_TX> --signers <TRUSTED_SIGNER_LIST> --threshold 1
```
It is worth noting that checkpoint-admin only supports clef as a signer for transactions and plain text(checkpoint). For more clef usage, please see the clef [tutorial](https://geth.ethereum.org/docs/tools/clef/tutorial) .
#### Sign
Checkpoint-admin provides two different modes of signing. You can automatically obtain the current stable checkpoint and sign it interactively, and you can also use the information provided by the command line flags to sign checkpoint offline.
**Interactive mode**
```shell
checkpoint-admin sign --clef <CLEF_ENDPOINT> --signer <SIGNER_TO_SIGN_CHECKPOINT> --rpc <NODE_RPC_ENDPOINT>
```
*It is worth noting that the connected Geth node can be a fullnode or a light client. If it is fullnode, you must enable the LES protocol. E.G. add `--light.serv 50` to the startup command line flags*.
**Offline mode**
```shell
checkpoint-admin sign --clef <CLEF_ENDPOINT> --signer <SIGNER_TO_SIGN_CHECKPOINT> --index <CHECKPOINT_INDEX> --hash <CHECKPOINT_HASH> --oracle <CHECKPOINT_ORACLE_ADDRESS>
```
*CHECKPOINT_HASH is obtained based on this [calculation method](https://github.com/ethereum/go-ethereum/blob/master/params/config.go#L251).*
#### Publish
Collect enough signatures from different trusted signers for the same checkpoint and submit them to oracle to update the "authenticated" checkpoint in the contract.
```shell
checkpoint-admin publish --clef <CLEF_ENDPOINT> --rpc <NODE_RPC_ENDPOINT> --signer <SIGNER_TO_SIGN_TX> --index <CHECKPOINT_INDEX> --signatures <CHECKPOINT_SIGNATURE_LIST>
```
#### Status query
Check the latest status of checkpoint oracle.
```shell
checkpoint-admin status --rpc <NODE_RPC_ENDPOINT>
```
### Enable checkpoint oracle in your private network
Currently, only the Ethereum mainnet and the default supported test networks (goerli) activate this feature. If you want to activate this feature in your private network, you can overwrite the relevant checkpoint oracle settings through the configuration file after deploying the oracle contract.
* Get your node configuration file `geth dumpconfig OTHER_COMMAND_LINE_OPTIONS > config.toml`
* Edit the configuration file and add the following information
```toml
[Eth.CheckpointOracle]
Address = CHECKPOINT_ORACLE_ADDRESS
Signers = [TRUSTED_SIGNER_1, ..., TRUSTED_SIGNER_N]
Threshold = THRESHOLD
```
* Start geth with the modified configuration file
*In the private network, all fullnodes and light clients need to be started using the same checkpoint oracle settings.*

View file

@ -1,133 +0,0 @@
// Copyright 2019 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"strconv"
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/external"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/contracts/checkpointoracle"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
// newClient creates a client with specified remote URL.
func newClient(ctx *cli.Context) *ethclient.Client {
client, err := ethclient.Dial(ctx.String(nodeURLFlag.Name))
if err != nil {
utils.Fatalf("Failed to connect to Ethereum node: %v", err)
}
return client
}
// newRPCClient creates a rpc client with specified node URL.
func newRPCClient(url string) *rpc.Client {
client, err := rpc.Dial(url)
if err != nil {
utils.Fatalf("Failed to connect to Ethereum node: %v", err)
}
return client
}
// getContractAddr retrieves the register contract address through
// rpc request.
func getContractAddr(client *rpc.Client) common.Address {
var addr string
if err := client.Call(&addr, "les_getCheckpointContractAddress"); err != nil {
utils.Fatalf("Failed to fetch checkpoint oracle address: %v", err)
}
return common.HexToAddress(addr)
}
// getCheckpoint retrieves the specified checkpoint or the latest one
// through rpc request.
func getCheckpoint(ctx *cli.Context, client *rpc.Client) *params.TrustedCheckpoint {
var checkpoint *params.TrustedCheckpoint
if ctx.IsSet(indexFlag.Name) {
var result [3]string
index := uint64(ctx.Int64(indexFlag.Name))
if err := client.Call(&result, "les_getCheckpoint", index); err != nil {
utils.Fatalf("Failed to get local checkpoint %v, please ensure the les API is exposed", err)
}
checkpoint = &params.TrustedCheckpoint{
SectionIndex: index,
SectionHead: common.HexToHash(result[0]),
CHTRoot: common.HexToHash(result[1]),
BloomRoot: common.HexToHash(result[2]),
}
} else {
var result [4]string
err := client.Call(&result, "les_latestCheckpoint")
if err != nil {
utils.Fatalf("Failed to get local checkpoint %v, please ensure the les API is exposed", err)
}
index, err := strconv.ParseUint(result[0], 0, 64)
if err != nil {
utils.Fatalf("Failed to parse checkpoint index %v", err)
}
checkpoint = &params.TrustedCheckpoint{
SectionIndex: index,
SectionHead: common.HexToHash(result[1]),
CHTRoot: common.HexToHash(result[2]),
BloomRoot: common.HexToHash(result[3]),
}
}
return checkpoint
}
// newContract creates a registrar contract instance with specified
// contract address or the default contracts for mainnet or testnet.
func newContract(client *rpc.Client) (common.Address, *checkpointoracle.CheckpointOracle) {
addr := getContractAddr(client)
if addr == (common.Address{}) {
utils.Fatalf("No specified registrar contract address")
}
contract, err := checkpointoracle.NewCheckpointOracle(addr, ethclient.NewClient(client))
if err != nil {
utils.Fatalf("Failed to setup registrar contract %s: %v", addr, err)
}
return addr, contract
}
// newClefSigner sets up a clef backend and returns a clef transaction signer.
func newClefSigner(ctx *cli.Context) *bind.TransactOpts {
clef, err := external.NewExternalSigner(ctx.String(clefURLFlag.Name))
if err != nil {
utils.Fatalf("Failed to create clef signer %v", err)
}
return bind.NewClefTransactor(clef, accounts.Account{Address: common.HexToAddress(ctx.String(signerFlag.Name))})
}

View file

@ -1,349 +0,0 @@
// Copyright 2019 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"bytes"
"context"
"encoding/binary"
"fmt"
"math/big"
"strings"
"time"
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/contracts/checkpointoracle"
"github.com/ethereum/go-ethereum/contracts/checkpointoracle/contract"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
var commandDeploy = &cli.Command{
Name: "deploy",
Usage: "Deploy a new checkpoint oracle contract",
Flags: []cli.Flag{
nodeURLFlag,
clefURLFlag,
signerFlag,
signersFlag,
thresholdFlag,
},
Action: deploy,
}
var commandSign = &cli.Command{
Name: "sign",
Usage: "Sign the checkpoint with the specified key",
Flags: []cli.Flag{
nodeURLFlag,
clefURLFlag,
signerFlag,
indexFlag,
hashFlag,
oracleFlag,
},
Action: sign,
}
var commandPublish = &cli.Command{
Name: "publish",
Usage: "Publish a checkpoint into the oracle",
Flags: []cli.Flag{
nodeURLFlag,
clefURLFlag,
signerFlag,
indexFlag,
signaturesFlag,
},
Action: publish,
}
// deploy deploys the checkpoint registrar contract.
//
// Note the network where the contract is deployed depends on
// the network where the connected node is located.
func deploy(ctx *cli.Context) error {
// Gather all the addresses that should be permitted to sign
var addrs []common.Address
for _, account := range strings.Split(ctx.String(signersFlag.Name), ",") {
if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) {
utils.Fatalf("Invalid account in --signers: '%s'", trimmed)
}
addrs = append(addrs, common.HexToAddress(account))
}
// Retrieve and validate the signing threshold
needed := ctx.Int(thresholdFlag.Name)
if needed == 0 || needed > len(addrs) {
utils.Fatalf("Invalid signature threshold %d", needed)
}
// Print a summary to ensure the user understands what they're signing
fmt.Printf("Deploying new checkpoint oracle:\n\n")
for i, addr := range addrs {
fmt.Printf("Admin %d => %s\n", i+1, addr.Hex())
}
fmt.Printf("\nSignatures needed to publish: %d\n", needed)
// setup clef signer, create an abigen transactor and an RPC client
transactor, client := newClefSigner(ctx), newClient(ctx)
// Deploy the checkpoint oracle
fmt.Println("Sending deploy request to Clef...")
oracle, tx, _, err := contract.DeployCheckpointOracle(transactor, client, addrs, big.NewInt(int64(params.CheckpointFrequency)),
big.NewInt(int64(params.CheckpointProcessConfirmations)), big.NewInt(int64(needed)))
if err != nil {
utils.Fatalf("Failed to deploy checkpoint oracle %v", err)
}
log.Info("Deployed checkpoint oracle", "address", oracle, "tx", tx.Hash().Hex())
return nil
}
// sign creates the signature for specific checkpoint
// with local key. Only contract admins have the permission to
// sign checkpoint.
func sign(ctx *cli.Context) error {
var (
offline bool // The indicator whether we sign checkpoint by offline.
chash common.Hash
cindex uint64
address common.Address
node *rpc.Client
oracle *checkpointoracle.CheckpointOracle
)
// nolint:nestif
if !ctx.IsSet(nodeURLFlag.Name) {
// Offline mode signing
offline = true
if !ctx.IsSet(hashFlag.Name) {
utils.Fatalf("Please specify the checkpoint hash (--hash) to sign in offline mode")
}
chash = common.HexToHash(ctx.String(hashFlag.Name))
if !ctx.IsSet(indexFlag.Name) {
utils.Fatalf("Please specify checkpoint index (--index) to sign in offline mode")
}
cindex = ctx.Uint64(indexFlag.Name)
if !ctx.IsSet(oracleFlag.Name) {
utils.Fatalf("Please specify oracle address (--oracle) to sign in offline mode")
}
address = common.HexToAddress(ctx.String(oracleFlag.Name))
} else {
// Interactive mode signing, retrieve the data from the remote node
node = newRPCClient(ctx.String(nodeURLFlag.Name))
checkpoint := getCheckpoint(ctx, node)
chash, cindex, address = checkpoint.Hash(), checkpoint.SectionIndex, getContractAddr(node)
// Check the validity of checkpoint
reqCtx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second)
defer cancelFn()
head, err := ethclient.NewClient(node).HeaderByNumber(reqCtx, nil)
if err != nil {
return err
}
num := head.Number.Uint64()
if num < ((cindex+1)*params.CheckpointFrequency + params.CheckpointProcessConfirmations) {
utils.Fatalf("Invalid future checkpoint")
}
_, oracle = newContract(node)
latest, _, h, err := oracle.Contract().GetLatestCheckpoint(nil)
if err != nil {
return err
}
if cindex < latest {
utils.Fatalf("Checkpoint is too old")
}
if cindex == latest && (latest != 0 || h.Uint64() != 0) {
utils.Fatalf("Stale checkpoint, latest registered %d, given %d", latest, cindex)
}
}
var (
signature string
signer string
)
// isAdmin checks whether the specified signer is admin.
isAdmin := func(addr common.Address) error {
signers, err := oracle.Contract().GetAllAdmin(nil)
if err != nil {
return err
}
for _, s := range signers {
if s == addr {
return nil
}
}
return fmt.Errorf("signer %v is not the admin", addr.Hex())
}
// Print to the user the data thy are about to sign
fmt.Printf("Oracle => %s\n", address.Hex())
fmt.Printf("Index %4d => %s\n", cindex, chash.Hex())
// Sign checkpoint in clef mode.
signer = ctx.String(signerFlag.Name)
if !offline {
if err := isAdmin(common.HexToAddress(signer)); err != nil {
return err
}
}
clef := newRPCClient(ctx.String(clefURLFlag.Name))
p := make(map[string]string)
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, cindex)
p["address"] = address.Hex()
p["message"] = hexutil.Encode(append(buf, chash.Bytes()...))
fmt.Println("Sending signing request to Clef...")
if err := clef.Call(&signature, "account_signData", accounts.MimetypeDataWithValidator, signer, p); err != nil {
utils.Fatalf("Failed to sign checkpoint, err %v", err)
}
fmt.Printf("Signer => %s\n", signer)
fmt.Printf("Signature => %s\n", signature)
return nil
}
// sighash calculates the hash of the data to sign for the checkpoint oracle.
func sighash(index uint64, oracle common.Address, hash common.Hash) []byte {
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, index)
data := append([]byte{0x19, 0x00}, append(oracle[:], append(buf, hash[:]...)...)...)
return crypto.Keccak256(data)
}
// ecrecover calculates the sender address from a sighash and signature combo.
func ecrecover(sighash []byte, sig []byte) common.Address {
sig[64] -= 27
defer func() { sig[64] += 27 }()
signer, err := crypto.SigToPub(sighash, sig)
if err != nil {
utils.Fatalf("Failed to recover sender from signature %x: %v", sig, err)
}
return crypto.PubkeyToAddress(*signer)
}
// publish registers the specified checkpoint which generated by connected node
// with a authorised private key.
func publish(ctx *cli.Context) error {
// Print the checkpoint oracle's current status to make sure we're interacting
// with the correct network and contract.
status(ctx)
// Gather the signatures from the CLI
var sigs [][]byte
for _, sig := range strings.Split(ctx.String(signaturesFlag.Name), ",") {
trimmed := strings.TrimPrefix(strings.TrimSpace(sig), "0x")
if len(trimmed) != 130 {
utils.Fatalf("Invalid signature in --signature: '%s'", trimmed)
} else {
sigs = append(sigs, common.Hex2Bytes(trimmed))
}
}
// Retrieve the checkpoint we want to sign to sort the signatures
var (
client = newRPCClient(ctx.String(nodeURLFlag.Name))
addr, oracle = newContract(client)
checkpoint = getCheckpoint(ctx, client)
sighash = sighash(checkpoint.SectionIndex, addr, checkpoint.Hash())
)
for i := 0; i < len(sigs); i++ {
for j := i + 1; j < len(sigs); j++ {
signerA := ecrecover(sighash, sigs[i])
signerB := ecrecover(sighash, sigs[j])
if bytes.Compare(signerA.Bytes(), signerB.Bytes()) > 0 {
sigs[i], sigs[j] = sigs[j], sigs[i]
}
}
}
// Retrieve recent header info to protect replay attack
reqCtx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second)
defer cancelFn()
head, err := ethclient.NewClient(client).HeaderByNumber(reqCtx, nil)
if err != nil {
return err
}
num := head.Number.Uint64()
recent, err := ethclient.NewClient(client).HeaderByNumber(reqCtx, big.NewInt(int64(num-128)))
if err != nil {
return err
}
// Print a summary of the operation that's going to be performed
fmt.Printf("Publishing %d => %s:\n\n", checkpoint.SectionIndex, checkpoint.Hash().Hex())
for i, sig := range sigs {
fmt.Printf("Signer %d => %s\n", i+1, ecrecover(sighash, sig).Hex())
}
fmt.Println()
fmt.Printf("Sentry number => %d\nSentry hash => %s\n", recent.Number, recent.Hash().Hex())
// Publish the checkpoint into the oracle
fmt.Println("Sending publish request to Clef...")
tx, err := oracle.RegisterCheckpoint(newClefSigner(ctx), checkpoint.SectionIndex, checkpoint.Hash().Bytes(), recent.Number, recent.Hash(), sigs)
if err != nil {
utils.Fatalf("Register contract failed %v", err)
}
log.Info("Successfully registered checkpoint", "tx", tx.Hash().Hex())
return nil
}

View file

@ -1,97 +0,0 @@
// Copyright 2019 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
// checkpoint-admin is a utility that can be used to query checkpoint information
// and register stable checkpoints into an oracle contract.
package main
import (
"fmt"
"os"
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log"
)
var app = flags.NewApp("ethereum checkpoint helper tool")
func init() {
app.Commands = []*cli.Command{
commandStatus,
commandDeploy,
commandSign,
commandPublish,
}
app.Flags = []cli.Flag{
oracleFlag,
nodeURLFlag,
}
}
// Commonly used command line flags.
var (
indexFlag = &cli.Int64Flag{
Name: "index",
Usage: "Checkpoint index (query latest from remote node if not specified)",
}
hashFlag = &cli.StringFlag{
Name: "hash",
Usage: "Checkpoint hash (query latest from remote node if not specified)",
}
oracleFlag = &cli.StringFlag{
Name: "oracle",
Usage: "Checkpoint oracle address (query from remote node if not specified)",
}
thresholdFlag = &cli.Int64Flag{
Name: "threshold",
Usage: "Minimal number of signatures required to approve a checkpoint",
}
nodeURLFlag = &cli.StringFlag{
Name: "rpc",
Value: "http://localhost:8545",
Usage: "The rpc endpoint of a local or remote geth node",
}
clefURLFlag = &cli.StringFlag{
Name: "clef",
Value: "http://localhost:8550",
Usage: "The rpc endpoint of clef",
}
signerFlag = &cli.StringFlag{
Name: "signer",
Usage: "Signer address for clef signing",
}
signersFlag = &cli.StringFlag{
Name: "signers",
Usage: "Comma separated accounts of trusted checkpoint signers",
}
signaturesFlag = &cli.StringFlag{
Name: "signatures",
Usage: "Comma separated checkpoint signatures to submit",
}
)
func main() {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
fdlimit.Raise(2048)
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

View file

@ -1,64 +0,0 @@
// Copyright 2019 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"fmt"
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/common"
)
var commandStatus = &cli.Command{
Name: "status",
Usage: "Fetches the signers and checkpoint status of the oracle contract",
Flags: []cli.Flag{
nodeURLFlag,
},
Action: status,
}
// status fetches the admin list of specified registrar contract.
func status(ctx *cli.Context) error {
// Create a wrapper around the checkpoint oracle contract
addr, oracle := newContract(newRPCClient(ctx.String(nodeURLFlag.Name)))
fmt.Printf("Oracle => %s\n", addr.Hex())
fmt.Println()
// Retrieve the list of authorized signers (admins)
admins, err := oracle.Contract().GetAllAdmin(nil)
if err != nil {
return err
}
for i, admin := range admins {
fmt.Printf("Admin %d => %s\n", i+1, admin.Hex())
}
fmt.Println()
// Retrieve the latest checkpoint
index, checkpoint, height, err := oracle.Contract().GetLatestCheckpoint(nil)
if err != nil {
return err
}
fmt.Printf("Checkpoint (published at #%d) %d => %s\n", height, index, common.Hash(checkpoint).Hex())
return nil
}

View file

@ -29,7 +29,7 @@ GLOBAL OPTIONS:
--loglevel value log level to emit to the screen (default: 4) --loglevel value log level to emit to the screen (default: 4)
--keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore") --keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore")
--configdir value Directory for Clef configuration (default: "$HOME/.clef") --configdir value Directory for Clef configuration (default: "$HOME/.clef")
--chainid value Chain id to use for signing (1=mainnet, 4=Rinkeby, 5=Goerli) (default: 1) --chainid value Chain id to use for signing (1=mainnet, 5=Goerli) (default: 1)
--lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength --lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength
--nousb Disables monitoring for and managing USB hardware wallets --nousb Disables monitoring for and managing USB hardware wallets
--pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm") --pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm")

View file

@ -27,6 +27,7 @@ import (
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
"net"
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
@ -99,7 +100,7 @@ var (
chainIdFlag = &cli.Int64Flag{ chainIdFlag = &cli.Int64Flag{
Name: "chainid", Name: "chainid",
Value: params.MainnetChainConfig.ChainID.Int64(), Value: params.MainnetChainConfig.ChainID.Int64(),
Usage: "Chain id to use for signing (1=mainnet, 4=Rinkeby, 5=Goerli)", Usage: "Chain id to use for signing (1=mainnet, 5=Goerli)",
} }
rpcPortFlag = &cli.IntFlag{ rpcPortFlag = &cli.IntFlag{
Name: "http.port", Name: "http.port",
@ -329,7 +330,7 @@ func initializeSecrets(c *cli.Context) error {
} }
if num != len(masterSeed) { if num != len(masterSeed) {
return fmt.Errorf("failed to read enough random") return errors.New("failed to read enough random")
} }
n, p := keystore.StandardScryptN, keystore.StandardScryptP n, p := keystore.StandardScryptN, keystore.StandardScryptP
@ -511,7 +512,7 @@ func initialize(c *cli.Context) error {
} }
} else if !c.Bool(acceptFlag.Name) { } else if !c.Bool(acceptFlag.Name) {
if !confirm(legalWarning) { if !confirm(legalWarning) {
return fmt.Errorf("aborted by user") return errors.New("aborted by user")
} }
fmt.Println() fmt.Println()
@ -816,6 +817,7 @@ func signer(c *cli.Context) error {
cors := utils.SplitAndTrim(c.String(utils.HTTPCORSDomainFlag.Name)) cors := utils.SplitAndTrim(c.String(utils.HTTPCORSDomainFlag.Name))
srv := rpc.NewServer("", 0, 0) srv := rpc.NewServer("", 0, 0)
srv.SetBatchLimits(node.DefaultConfig.BatchRequestLimit, node.DefaultConfig.BatchResponseMaxSize)
err := node.RegisterApis(rpcAPI, []string{"account"}, srv) err := node.RegisterApis(rpcAPI, []string{"account"}, srv)
if err != nil { if err != nil {
utils.Fatalf("Could not register API: %w", err) utils.Fatalf("Could not register API: %w", err)
@ -827,8 +829,7 @@ func signer(c *cli.Context) error {
port := c.Int(rpcPortFlag.Name) port := c.Int(rpcPortFlag.Name)
// start http server // start http server
httpEndpoint := fmt.Sprintf("%s:%d", c.String(utils.HTTPListenAddrFlag.Name), port) httpEndpoint := net.JoinHostPort(c.String(utils.HTTPListenAddrFlag.Name), fmt.Sprintf("%d", port))
httpServer, addr, err := node.StartHTTPEndpoint(httpEndpoint, rpc.DefaultHTTPTimeouts, handler) httpServer, addr, err := node.StartHTTPEndpoint(httpEndpoint, rpc.DefaultHTTPTimeouts, handler)
if err != nil { if err != nil {
utils.Fatalf("Could not start RPC api: %v", err) utils.Fatalf("Could not start RPC api: %v", err)
@ -946,7 +947,7 @@ func readMasterKey(ctx *cli.Context, ui core.UIClientAPI) ([]byte, error) {
masterSeed, err := decryptSeed(cipherKey, password) masterSeed, err := decryptSeed(cipherKey, password)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to decrypt the master seed of clef") return nil, errors.New("failed to decrypt the master seed of clef")
} }
if len(masterSeed) < 256 { if len(masterSeed) < 256 {

View file

@ -93,11 +93,11 @@ func (c *crawler) run(timeout time.Duration, nthreads int) nodeSet {
} }
var ( var (
added uint64 added atomic.Uint64
updated uint64 updated atomic.Uint64
skipped uint64 skipped atomic.Uint64
recent uint64 recent atomic.Uint64
removed uint64 removed atomic.Uint64
wg sync.WaitGroup wg sync.WaitGroup
) )
@ -112,15 +112,15 @@ func (c *crawler) run(timeout time.Duration, nthreads int) nodeSet {
case n := <-c.ch: case n := <-c.ch:
switch c.updateNode(n) { switch c.updateNode(n) {
case nodeSkipIncompat: case nodeSkipIncompat:
atomic.AddUint64(&skipped, 1) skipped.Add(1)
case nodeSkipRecent: case nodeSkipRecent:
atomic.AddUint64(&recent, 1) recent.Add(1)
case nodeRemoved: case nodeRemoved:
atomic.AddUint64(&removed, 1) removed.Add(1)
case nodeAdded: case nodeAdded:
atomic.AddUint64(&added, 1) added.Add(1)
default: default:
atomic.AddUint64(&updated, 1) updated.Add(1)
} }
case <-c.closed: case <-c.closed:
return return
@ -147,11 +147,11 @@ loop:
break loop break loop
case <-statusTicker.C: case <-statusTicker.C:
log.Info("Crawling in progress", log.Info("Crawling in progress",
"added", atomic.LoadUint64(&added), "added", added.Load(),
"updated", atomic.LoadUint64(&updated), "updated", updated.Load(),
"removed", atomic.LoadUint64(&removed), "removed", removed.Load(),
"ignored(recent)", atomic.LoadUint64(&recent), "ignored(recent)", recent.Load(),
"ignored(incompatible)", atomic.LoadUint64(&skipped)) "ignored(incompatible)", skipped.Load())
} }
} }

View file

@ -17,6 +17,7 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"net" "net"
"strconv" "strconv"
@ -187,7 +188,7 @@ func discv4Resolve(ctx *cli.Context) error {
func discv4ResolveJSON(ctx *cli.Context) error { func discv4ResolveJSON(ctx *cli.Context) error {
if ctx.NArg() < 1 { if ctx.NArg() < 1 {
return fmt.Errorf("need nodes file as argument") return errors.New("need nodes file as argument")
} }
nodesFile := ctx.Args().Get(0) nodesFile := ctx.Args().Get(0)
@ -222,7 +223,7 @@ func discv4ResolveJSON(ctx *cli.Context) error {
func discv4Crawl(ctx *cli.Context) error { func discv4Crawl(ctx *cli.Context) error {
if ctx.NArg() < 1 { if ctx.NArg() < 1 {
return fmt.Errorf("need nodes file as argument") return errors.New("need nodes file as argument")
} }
nodesFile := ctx.Args().First() nodesFile := ctx.Args().First()
@ -376,8 +377,7 @@ func listen(ctx *cli.Context, ln *enode.LocalNode) *net.UDPConn {
} }
func parseBootnodes(ctx *cli.Context) ([]*enode.Node, error) { func parseBootnodes(ctx *cli.Context) ([]*enode.Node, error) {
s := params.RinkebyBootnodes s := params.MainnetBootnodes
if ctx.IsSet(bootnodesFlag.Name) { if ctx.IsSet(bootnodesFlag.Name) {
input := ctx.String(bootnodesFlag.Name) input := ctx.String(bootnodesFlag.Name)
if input == "" { if input == "" {

View file

@ -17,6 +17,7 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"time" "time"
@ -103,7 +104,7 @@ func discv5Resolve(ctx *cli.Context) error {
func discv5Crawl(ctx *cli.Context) error { func discv5Crawl(ctx *cli.Context) error {
if ctx.NArg() < 1 { if ctx.NArg() < 1 {
return fmt.Errorf("need nodes file as argument") return errors.New("need nodes file as argument")
} }
nodesFile := ctx.Args().First() nodesFile := ctx.Args().First()

View file

@ -18,6 +18,7 @@ package main
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"strings" "strings"
@ -49,7 +50,7 @@ type cloudflareClient struct {
func newCloudflareClient(ctx *cli.Context) *cloudflareClient { func newCloudflareClient(ctx *cli.Context) *cloudflareClient {
token := ctx.String(cloudflareTokenFlag.Name) token := ctx.String(cloudflareTokenFlag.Name)
if token == "" { if token == "" {
exit(fmt.Errorf("need cloudflare API token to proceed")) exit(errors.New("need cloudflare API token to proceed"))
} }
api, err := cloudflare.NewWithAPIToken(token) api, err := cloudflare.NewWithAPIToken(token)

View file

@ -20,7 +20,6 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -34,6 +33,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/route53/types" "github.com/aws/aws-sdk-go-v2/service/route53/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/dnsdisc" "github.com/ethereum/go-ethereum/p2p/dnsdisc"
"golang.org/x/exp/slices"
) )
const ( const (
@ -83,7 +83,7 @@ func newRoute53Client(ctx *cli.Context) *route53Client {
asec := ctx.String(route53AccessSecretFlag.Name) asec := ctx.String(route53AccessSecretFlag.Name)
if akey == "" || asec == "" { if akey == "" || asec == "" {
exit(fmt.Errorf("need Route53 Access Key ID and secret to proceed")) exit(errors.New("need Route53 Access Key ID and secret to proceed"))
} }
creds := aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(akey, asec, "")) creds := aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(akey, asec, ""))
@ -318,13 +318,17 @@ func makeDeletionChanges(records map[string]recordSet, keep map[string]string) [
// sortChanges ensures DNS changes are in leaf-added -> root-changed -> leaf-deleted order. // sortChanges ensures DNS changes are in leaf-added -> root-changed -> leaf-deleted order.
func sortChanges(changes []types.Change) { func sortChanges(changes []types.Change) {
score := map[string]int{"CREATE": 1, "UPSERT": 2, "DELETE": 3} score := map[string]int{"CREATE": 1, "UPSERT": 2, "DELETE": 3}
slices.SortFunc(changes, func(a, b types.Change) int {
sort.Slice(changes, func(i, j int) bool { if a.Action == b.Action {
if changes[i].Action == changes[j].Action { return strings.Compare(*a.ResourceRecordSet.Name, *b.ResourceRecordSet.Name)
return *changes[i].ResourceRecordSet.Name < *changes[j].ResourceRecordSet.Name
} }
if score[string(a.Action)] < score[string(b.Action)] {
return score[string(changes[i].Action)] < score[string(changes[j].Action)] return -1
}
if score[string(a.Action)] > score[string(b.Action)] {
return 1
}
return 0
}) })
} }

View file

@ -19,6 +19,7 @@ package main
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
@ -152,7 +153,7 @@ func dnsSync(ctx *cli.Context) error {
func dnsSign(ctx *cli.Context) error { func dnsSign(ctx *cli.Context) error {
if ctx.NArg() < 2 { if ctx.NArg() < 2 {
return fmt.Errorf("need tree definition directory and key file as arguments") return errors.New("need tree definition directory and key file as arguments")
} }
var ( var (
@ -215,7 +216,7 @@ func directoryName(dir string) string {
// dnsToTXT performs dnsTXTCommand. // dnsToTXT performs dnsTXTCommand.
func dnsToTXT(ctx *cli.Context) error { func dnsToTXT(ctx *cli.Context) error {
if ctx.NArg() < 1 { if ctx.NArg() < 1 {
return fmt.Errorf("need tree definition directory as argument") return errors.New("need tree definition directory as argument")
} }
output := ctx.Args().Get(1) output := ctx.Args().Get(1)
@ -236,7 +237,7 @@ func dnsToTXT(ctx *cli.Context) error {
// dnsToCloudflare performs dnsCloudflareCommand. // dnsToCloudflare performs dnsCloudflareCommand.
func dnsToCloudflare(ctx *cli.Context) error { func dnsToCloudflare(ctx *cli.Context) error {
if ctx.NArg() != 1 { if ctx.NArg() != 1 {
return fmt.Errorf("need tree definition directory as argument") return errors.New("need tree definition directory as argument")
} }
domain, t, err := loadTreeDefinitionForExport(ctx.Args().Get(0)) domain, t, err := loadTreeDefinitionForExport(ctx.Args().Get(0))
@ -252,7 +253,7 @@ func dnsToCloudflare(ctx *cli.Context) error {
// dnsToRoute53 performs dnsRoute53Command. // dnsToRoute53 performs dnsRoute53Command.
func dnsToRoute53(ctx *cli.Context) error { func dnsToRoute53(ctx *cli.Context) error {
if ctx.NArg() != 1 { if ctx.NArg() != 1 {
return fmt.Errorf("need tree definition directory as argument") return errors.New("need tree definition directory as argument")
} }
domain, t, err := loadTreeDefinitionForExport(ctx.Args().Get(0)) domain, t, err := loadTreeDefinitionForExport(ctx.Args().Get(0))
@ -268,7 +269,7 @@ func dnsToRoute53(ctx *cli.Context) error {
// dnsNukeRoute53 performs dnsRoute53NukeCommand. // dnsNukeRoute53 performs dnsRoute53NukeCommand.
func dnsNukeRoute53(ctx *cli.Context) error { func dnsNukeRoute53(ctx *cli.Context) error {
if ctx.NArg() != 1 { if ctx.NArg() != 1 {
return fmt.Errorf("need domain name as argument") return errors.New("need domain name as argument")
} }
client := newRoute53Client(ctx) client := newRoute53Client(ctx)
@ -404,11 +405,11 @@ func loadTreeDefinitionForExport(dir string) (domain string, t *dnsdisc.Tree, er
// tree's signature if valid. // tree's signature if valid.
func ensureValidTreeSignature(t *dnsdisc.Tree, pubkey *ecdsa.PublicKey, sig string) error { func ensureValidTreeSignature(t *dnsdisc.Tree, pubkey *ecdsa.PublicKey, sig string) error {
if sig == "" { if sig == "" {
return fmt.Errorf("missing signature, run 'devp2p dns sign' first") return errors.New("missing signature, run 'devp2p dns sign' first")
} }
if err := t.SetSignature(pubkey, sig); err != nil { if err := t.SetSignature(pubkey, sig); err != nil {
return fmt.Errorf("invalid signature on tree, run 'devp2p dns sign' to update it") return errors.New("invalid signature on tree, run 'devp2p dns sign' to update it")
} }
return nil return nil

View file

@ -20,6 +20,7 @@ import (
"bytes" "bytes"
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"io" "io"
"net" "net"
@ -51,7 +52,7 @@ func enrdump(ctx *cli.Context) error {
// nolint:nestif // nolint:nestif
if file := ctx.String(fileFlag.Name); file != "" { if file := ctx.String(fileFlag.Name); file != "" {
if ctx.NArg() != 0 { if ctx.NArg() != 0 {
return fmt.Errorf("can't dump record from command-line argument in -file mode") return errors.New("can't dump record from command-line argument in -file mode")
} }
var b []byte var b []byte
@ -71,7 +72,7 @@ func enrdump(ctx *cli.Context) error {
} else if ctx.NArg() == 1 { } else if ctx.NArg() == 1 {
source = ctx.Args().First() source = ctx.Args().First()
} else { } else {
return fmt.Errorf("need record as argument") return errors.New("need record as argument")
} }
r, err := parseRecord(source) r, err := parseRecord(source)

View file

@ -19,6 +19,7 @@ package ethtest
import ( import (
"compress/gzip" "compress/gzip"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
@ -104,7 +105,7 @@ func (c *Chain) Head() *types.Block {
// nolint:typecheck // nolint:typecheck
func (c *Chain) GetHeaders(req *GetBlockHeaders) ([]*types.Header, error) { func (c *Chain) GetHeaders(req *GetBlockHeaders) ([]*types.Header, error) {
if req.Amount < 1 { if req.Amount < 1 {
return nil, fmt.Errorf("no block headers requested") return nil, errors.New("no block headers requested")
} }
headers := make([]*types.Header, req.Amount) headers := make([]*types.Header, req.Amount)

View file

@ -17,6 +17,7 @@
package ethtest package ethtest
import ( import (
"errors"
"fmt" "fmt"
"net" "net"
"reflect" "reflect"
@ -199,7 +200,7 @@ loop:
} }
// make sure eth protocol version is set for negotiation // make sure eth protocol version is set for negotiation
if c.negotiatedProtoVersion == 0 { if c.negotiatedProtoVersion == 0 {
return nil, fmt.Errorf("eth protocol version must be set in Conn") return nil, errors.New("eth protocol version must be set in Conn")
} }
if status == nil { if status == nil {

View file

@ -116,15 +116,13 @@ func setupGeth(stack *node.Node) error {
} }
backend, err := eth.New(stack, &ethconfig.Config{ backend, err := eth.New(stack, &ethconfig.Config{
Genesis: &chain.genesis, Genesis: &chain.genesis,
NetworkId: chain.genesis.Config.ChainID.Uint64(), // 19763 NetworkId: chain.genesis.Config.ChainID.Uint64(), // 19763
DatabaseCache: 10, DatabaseCache: 10,
TrieCleanCache: 10, TrieCleanCache: 10,
TrieCleanCacheJournal: "", TrieDirtyCache: 16,
TrieCleanCacheRejournal: 60 * time.Minute, TrieTimeout: 60 * time.Minute,
TrieDirtyCache: 16, SnapshotCache: 10,
TrieTimeout: 60 * time.Minute,
SnapshotCache: 10,
}) })
if err != nil { if err != nil {
return err return err

View file

@ -6,6 +6,7 @@
"eip155Block": 0, "eip155Block": 0,
"eip158Block": 0, "eip158Block": 0,
"byzantiumBlock": 0, "byzantiumBlock": 0,
"terminalTotalDifficultyPassed": true,
"ethash": {} "ethash": {}
}, },
"nonce": "0xdeadbeefdeadbeef", "nonce": "0xdeadbeefdeadbeef",

View file

@ -17,6 +17,7 @@
package ethtest package ethtest
import ( import (
"errors"
"fmt" "fmt"
"math/big" "math/big"
"strings" "strings"
@ -39,7 +40,7 @@ func (s *Suite) sendSuccessfulTxs(t *utesting.T) error {
} }
for i, tx := range tests { for i, tx := range tests {
if tx == nil { if tx == nil {
return fmt.Errorf("could not find tx to send") return errors.New("could not find tx to send")
} }
t.Logf("Testing tx propagation %d: sending tx %v %v %v\n", i, tx.Hash().String(), tx.GasPrice(), tx.Gas()) t.Logf("Testing tx propagation %d: sending tx %v %v %v\n", i, tx.Hash().String(), tx.GasPrice(), tx.Gas())
@ -383,7 +384,7 @@ func generateTxs(s *Suite, numTxs int) (map[common.Hash]common.Hash, []*types.Tr
nextTx := getNextTxFromChain(s) nextTx := getNextTxFromChain(s)
if nextTx == nil { if nextTx == nil {
return nil, nil, fmt.Errorf("failed to get the next transaction") return nil, nil, errors.New("failed to get the next transaction")
} }
gas := nextTx.Gas() gas := nextTx.Gas()
@ -393,7 +394,7 @@ func generateTxs(s *Suite, numTxs int) (map[common.Hash]common.Hash, []*types.Tr
for i := 0; i < numTxs; i++ { for i := 0; i < numTxs; i++ {
tx := generateTx(s.chain.chainConfig, nonce, gas) tx := generateTx(s.chain.chainConfig, nonce, gas)
if tx == nil { if tx == nil {
return nil, nil, fmt.Errorf("failed to get the next transaction") return nil, nil, errors.New("failed to get the next transaction")
} }
txHashMap[tx.Hash()] = tx.Hash() txHashMap[tx.Hash()] = tx.Hash()

View file

@ -18,6 +18,7 @@ package ethtest
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"errors"
"fmt" "fmt"
"time" "time"
@ -302,6 +303,5 @@ func (c *Conn) ReadSnap(id uint64) (Message, error) {
return snpMsg.(Message), nil return snpMsg.(Message), nil
} }
return nil, errors.New("request timed out")
return nil, fmt.Errorf("request timed out")
} }

View file

@ -19,6 +19,7 @@ package v4test
import ( import (
"bytes" "bytes"
"crypto/rand" "crypto/rand"
"errors"
"fmt" "fmt"
"net" "net"
"time" "time"
@ -124,7 +125,7 @@ func (te *testenv) checkPingPong(pingHash []byte) error {
// and a PING. The two packets do not have to be in any particular order. // and a PING. The two packets do not have to be in any particular order.
func (te *testenv) checkPong(reply v4wire.Packet, pingHash []byte) error { func (te *testenv) checkPong(reply v4wire.Packet, pingHash []byte) error {
if reply == nil { if reply == nil {
return fmt.Errorf("expected PONG reply, got nil") return errors.New("expected PONG reply, got nil")
} }
if reply.Kind() != v4wire.PongPacket { if reply.Kind() != v4wire.PongPacket {

View file

@ -17,6 +17,7 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"net" "net"
@ -87,7 +88,7 @@ var (
func genkey(ctx *cli.Context) error { func genkey(ctx *cli.Context) error {
if ctx.NArg() != 1 { if ctx.NArg() != 1 {
return fmt.Errorf("need key file as argument") return errors.New("need key file as argument")
} }
file := ctx.Args().Get(0) file := ctx.Args().Get(0)
@ -135,7 +136,7 @@ func keyToRecord(ctx *cli.Context) error {
func makeRecord(ctx *cli.Context) (*enode.Node, error) { func makeRecord(ctx *cli.Context) (*enode.Node, error) {
if ctx.NArg() != 1 { if ctx.NArg() != 1 {
return nil, fmt.Errorf("need key file as argument") return nil, errors.New("need key file as argument")
} }
var ( var (

View file

@ -21,11 +21,11 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"sort"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"golang.org/x/exp/slices"
) )
const jsonIndent = " " const jsonIndent = " "
@ -80,8 +80,8 @@ func (ns nodeSet) nodes() []*enode.Node {
result = append(result, n.N) result = append(result, n.N)
} }
// Sort by ID. // Sort by ID.
sort.Slice(result, func(i, j int) bool { slices.SortFunc(result, func(a, b *enode.Node) int {
return bytes.Compare(result[i].ID().Bytes(), result[j].ID().Bytes()) < 0 return bytes.Compare(a.ID().Bytes(), b.ID().Bytes())
}) })
return result return result
@ -107,9 +107,14 @@ func (ns nodeSet) topN(n int) nodeSet {
for _, v := range ns { for _, v := range ns {
byscore = append(byscore, v) byscore = append(byscore, v)
} }
slices.SortFunc(byscore, func(a, b nodeJSON) int {
sort.Slice(byscore, func(i, j int) bool { if a.Score > b.Score {
return byscore[i].Score >= byscore[j].Score return -1
}
if a.Score < b.Score {
return 1
}
return 0
}) })
result := make(nodeSet, n) result := make(nodeSet, n)

View file

@ -60,7 +60,7 @@ var (
func nodesetInfo(ctx *cli.Context) error { func nodesetInfo(ctx *cli.Context) error {
if ctx.NArg() < 1 { if ctx.NArg() < 1 {
return fmt.Errorf("need nodes file as argument") return errors.New("need nodes file as argument")
} }
ns := loadNodesJSON(ctx.Args().First()) ns := loadNodesJSON(ctx.Args().First())
@ -108,7 +108,7 @@ func showAttributeCounts(ns nodeSet) {
func nodesetFilter(ctx *cli.Context) error { func nodesetFilter(ctx *cli.Context) error {
if ctx.NArg() < 1 { if ctx.NArg() < 1 {
return fmt.Errorf("need nodes file as argument") return errors.New("need nodes file as argument")
} }
// Parse -limit. // Parse -limit.
limit, err := parseFilterLimit(ctx.Args().Tail()) limit, err := parseFilterLimit(ctx.Args().Tail())

View file

@ -17,6 +17,7 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"net" "net"
@ -98,7 +99,7 @@ func rlpxPing(ctx *cli.Context) error {
case 1: case 1:
var msg []p2p.DiscReason var msg []p2p.DiscReason
if rlp.DecodeBytes(data, &msg); len(msg) == 0 { if rlp.DecodeBytes(data, &msg); len(msg) == 0 {
return fmt.Errorf("invalid disconnect message") return errors.New("invalid disconnect message")
} }
return fmt.Errorf("received disconnect message: %v", msg[0]) return fmt.Errorf("received disconnect message: %v", msg[0])

View file

@ -342,7 +342,7 @@ To make `t8n` apply these, the following inputs are required:
- For ethash, it is `5000000000000000000` `wei`, - For ethash, it is `5000000000000000000` `wei`,
- If this is not defined, mining rewards are not applied, - If this is not defined, mining rewards are not applied,
- A value of `0` is valid, and causes accounts to be 'touched'. - A value of `0` is valid, and causes accounts to be 'touched'.
- For each ommer, the tool needs to be given an `addres\` and a `delta`. This - For each ommer, the tool needs to be given an `address\` and a `delta`. This
is done via the `ommers` field in `env`. is done via the `ommers` field in `env`.
Note: the tool does not verify that e.g. the normal uncle rules apply, Note: the tool does not verify that e.g. the normal uncle rules apply,

View file

@ -24,6 +24,8 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/tests" "github.com/ethereum/go-ethereum/tests"
) )
@ -43,7 +45,16 @@ func blockTestCmd(ctx *cli.Context) error {
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name)))
log.Root().SetHandler(glogger) log.Root().SetHandler(glogger)
var tracer vm.EVMLogger
// Configure the EVM logger
if ctx.Bool(MachineFlag.Name) {
tracer = logger.NewJSONLogger(&logger.Config{
EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
DisableStack: ctx.Bool(DisableStackFlag.Name),
DisableStorage: ctx.Bool(DisableStorageFlag.Name),
EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
}, os.Stderr)
}
// Load the test content from the input file // Load the test content from the input file
src, err := os.ReadFile(ctx.Args().First()) src, err := os.ReadFile(ctx.Args().First())
if err != nil { if err != nil {
@ -57,7 +68,7 @@ func blockTestCmd(ctx *cli.Context) error {
} }
for i, test := range tests { for i, test := range tests {
if err := test.Run(false); err != nil { if err := test.Run(false, tracer); err != nil {
return fmt.Errorf("test %v: %w", i, err) return fmt.Errorf("test %v: %w", i, err)
} }
} }

View file

@ -17,7 +17,6 @@
package t8ntool package t8ntool
import ( import (
"context"
"crypto/ecdsa" "crypto/ecdsa"
"encoding/json" "encoding/json"
"errors" "errors"
@ -31,7 +30,6 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/consensus/clique"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -76,11 +74,9 @@ type bbInput struct {
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
Clique *cliqueInput `json:"clique,omitempty"` Clique *cliqueInput `json:"clique,omitempty"`
Ethash bool `json:"-"` Ethash bool `json:"-"`
EthashDir string `json:"-"` Txs []*types.Transaction `json:"-"`
PowMode ethash.Mode `json:"-"` Ommers []*types.Header `json:"-"`
Txs []*types.Transaction `json:"-"`
Ommers []*types.Header `json:"-"`
} }
type cliqueInput struct { type cliqueInput struct {
@ -175,8 +171,6 @@ func (i *bbInput) ToBlock() *types.Block {
// SealBlock seals the given block using the configured engine. // SealBlock seals the given block using the configured engine.
func (i *bbInput) SealBlock(block *types.Block) (*types.Block, error) { func (i *bbInput) SealBlock(block *types.Block) (*types.Block, error) {
switch { switch {
case i.Ethash:
return i.sealEthash(block)
case i.Clique != nil: case i.Clique != nil:
return i.sealClique(block) return i.sealClique(block)
default: default:
@ -184,50 +178,19 @@ func (i *bbInput) SealBlock(block *types.Block) (*types.Block, error) {
} }
} }
// sealEthash seals the given block using ethash.
func (i *bbInput) sealEthash(block *types.Block) (*types.Block, error) {
if i.Header.Nonce != nil {
return nil, NewError(ErrorConfig, fmt.Errorf("sealing with ethash will overwrite provided nonce"))
}
ethashConfig := ethash.Config{
PowMode: i.PowMode,
DatasetDir: i.EthashDir,
CacheDir: i.EthashDir,
DatasetsInMem: 1,
DatasetsOnDisk: 2,
CachesInMem: 2,
CachesOnDisk: 3,
}
engine := ethash.New(ethashConfig, nil, true)
defer engine.Close()
// Use a buffered chan for results.
// If the testmode is used, the sealer will return quickly, and complain
// "Sealing result is not read by miner" if it cannot write the result.
results := make(chan *types.Block, 1)
if err := engine.Seal(context.Background(), nil, block, results, nil); err != nil {
panic(fmt.Sprintf("failed to seal block: %v", err))
}
found := <-results
return block.WithSeal(found.Header()), nil
}
// sealClique seals the given block using clique. // sealClique seals the given block using clique.
func (i *bbInput) sealClique(block *types.Block) (*types.Block, error) { func (i *bbInput) sealClique(block *types.Block) (*types.Block, error) {
// If any clique value overwrites an explicit header value, fail // If any clique value overwrites an explicit header value, fail
// to avoid silently building a block with unexpected values. // to avoid silently building a block with unexpected values.
if i.Header.Extra != nil { if i.Header.Extra != nil {
return nil, NewError(ErrorConfig, fmt.Errorf("sealing with clique will overwrite provided extra data")) return nil, NewError(ErrorConfig, errors.New("sealing with clique will overwrite provided extra data"))
} }
header := block.Header() header := block.Header()
if i.Clique.Voted != nil { if i.Clique.Voted != nil {
if i.Header.Coinbase != nil { if i.Header.Coinbase != nil {
return nil, NewError(ErrorConfig, fmt.Errorf("sealing with clique and voting will overwrite provided coinbase")) return nil, NewError(ErrorConfig, errors.New("sealing with clique and voting will overwrite provided coinbase"))
} }
header.Coinbase = *i.Clique.Voted header.Coinbase = *i.Clique.Voted
@ -235,7 +198,7 @@ func (i *bbInput) sealClique(block *types.Block) (*types.Block, error) {
if i.Clique.Authorize != nil { if i.Clique.Authorize != nil {
if i.Header.Nonce != nil { if i.Header.Nonce != nil {
return nil, NewError(ErrorConfig, fmt.Errorf("sealing with clique and voting will overwrite provided nonce")) return nil, NewError(ErrorConfig, errors.New("sealing with clique and voting will overwrite provided nonce"))
} }
if *i.Clique.Authorize { if *i.Clique.Authorize {
@ -296,32 +259,8 @@ func readInput(ctx *cli.Context) (*bbInput, error) {
withdrawalsStr = ctx.String(InputWithdrawalsFlag.Name) withdrawalsStr = ctx.String(InputWithdrawalsFlag.Name)
txsStr = ctx.String(InputTxsRlpFlag.Name) txsStr = ctx.String(InputTxsRlpFlag.Name)
cliqueStr = ctx.String(SealCliqueFlag.Name) cliqueStr = ctx.String(SealCliqueFlag.Name)
ethashOn = ctx.Bool(SealEthashFlag.Name)
ethashDir = ctx.String(SealEthashDirFlag.Name)
ethashMode = ctx.String(SealEthashModeFlag.Name)
inputData = &bbInput{} inputData = &bbInput{}
) )
if ethashOn && cliqueStr != "" {
return nil, NewError(ErrorConfig, fmt.Errorf("both ethash and clique sealing specified, only one may be chosen"))
}
if ethashOn {
inputData.Ethash = ethashOn
inputData.EthashDir = ethashDir
switch ethashMode {
case "normal":
inputData.PowMode = ethash.ModeNormal
case "test":
inputData.PowMode = ethash.ModeTest
case "fake":
inputData.PowMode = ethash.ModeFake
default:
return nil, NewError(ErrorConfig, fmt.Errorf("unknown pow mode: %s, supported modes: test, fake, normal", ethashMode))
}
}
if headerStr == stdinSelector || ommersStr == stdinSelector || txsStr == stdinSelector || cliqueStr == stdinSelector { if headerStr == stdinSelector || ommersStr == stdinSelector || txsStr == stdinSelector || cliqueStr == stdinSelector {
decoder := json.NewDecoder(os.Stdin) decoder := json.NewDecoder(os.Stdin)
if err := decoder.Decode(inputData); err != nil { if err := decoder.Decode(inputData); err != nil {
@ -407,7 +346,7 @@ func readInput(ctx *cli.Context) (*bbInput, error) {
return inputData, nil return inputData, nil
} }
// dispatchOutput writes the output data to either stderr or stdout, or to the specified // dispatchBlock writes the output data to either stderr or stdout, or to the specified
// files // files
func dispatchBlock(ctx *cli.Context, baseDir string, block *types.Block) error { func dispatchBlock(ctx *cli.Context, baseDir string, block *types.Block) error {
raw, _ := rlp.EncodeToBytes(block) raw, _ := rlp.EncodeToBytes(block)

View file

@ -19,12 +19,12 @@ package t8ntool
import ( import (
"fmt" "fmt"
"math/big" "math/big"
"os"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
@ -47,17 +47,19 @@ type Prestate struct {
// ExecutionResult contains the execution status after running a state test, any // ExecutionResult contains the execution status after running a state test, any
// error that might have occurred and a dump of the final state if requested. // error that might have occurred and a dump of the final state if requested.
type ExecutionResult struct { type ExecutionResult struct {
StateRoot common.Hash `json:"stateRoot"` StateRoot common.Hash `json:"stateRoot"`
TxRoot common.Hash `json:"txRoot"` TxRoot common.Hash `json:"txRoot"`
ReceiptRoot common.Hash `json:"receiptsRoot"` ReceiptRoot common.Hash `json:"receiptsRoot"`
LogsHash common.Hash `json:"logsHash"` LogsHash common.Hash `json:"logsHash"`
Bloom types.Bloom `json:"logsBloom" gencodec:"required"` Bloom types.Bloom `json:"logsBloom" gencodec:"required"`
Receipts types.Receipts `json:"receipts"` Receipts types.Receipts `json:"receipts"`
Rejected []*rejectedTx `json:"rejected,omitempty"` Rejected []*rejectedTx `json:"rejected,omitempty"`
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"` Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
GasUsed math.HexOrDecimal64 `json:"gasUsed"` GasUsed math.HexOrDecimal64 `json:"gasUsed"`
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"` WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"`
CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"`
CurrentBlobGasUsed *math.HexOrDecimal64 `json:"currentBlobGasUsed,omitempty"`
} }
type ommer struct { type ommer struct {
@ -67,37 +69,43 @@ type ommer struct {
//go:generate go run github.com/fjl/gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go //go:generate go run github.com/fjl/gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go
type stEnv struct { type stEnv struct {
Coinbase common.Address `json:"currentCoinbase" gencodec:"required"` Coinbase common.Address `json:"currentCoinbase" gencodec:"required"`
Difficulty *big.Int `json:"currentDifficulty"` Difficulty *big.Int `json:"currentDifficulty"`
Random *big.Int `json:"currentRandom"` Random *big.Int `json:"currentRandom"`
ParentDifficulty *big.Int `json:"parentDifficulty"` ParentDifficulty *big.Int `json:"parentDifficulty"`
ParentBaseFee *big.Int `json:"parentBaseFee,omitempty"` ParentBaseFee *big.Int `json:"parentBaseFee,omitempty"`
ParentGasUsed uint64 `json:"parentGasUsed,omitempty"` ParentGasUsed uint64 `json:"parentGasUsed,omitempty"`
ParentGasLimit uint64 `json:"parentGasLimit,omitempty"` ParentGasLimit uint64 `json:"parentGasLimit,omitempty"`
GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` GasLimit uint64 `json:"currentGasLimit" gencodec:"required"`
Number uint64 `json:"currentNumber" gencodec:"required"` Number uint64 `json:"currentNumber" gencodec:"required"`
Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` Timestamp uint64 `json:"currentTimestamp" gencodec:"required"`
ParentTimestamp uint64 `json:"parentTimestamp,omitempty"` ParentTimestamp uint64 `json:"parentTimestamp,omitempty"`
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
Ommers []ommer `json:"ommers,omitempty"` Ommers []ommer `json:"ommers,omitempty"`
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
BaseFee *big.Int `json:"currentBaseFee,omitempty"` BaseFee *big.Int `json:"currentBaseFee,omitempty"`
ParentUncleHash common.Hash `json:"parentUncleHash"` ParentUncleHash common.Hash `json:"parentUncleHash"`
ExcessBlobGas *uint64 `json:"excessBlobGas,omitempty"`
ParentExcessBlobGas *uint64 `json:"parentExcessBlobGas,omitempty"`
ParentBlobGasUsed *uint64 `json:"parentBlobGasUsed,omitempty"`
} }
type stEnvMarshaling struct { type stEnvMarshaling struct {
Coinbase common.UnprefixedAddress Coinbase common.UnprefixedAddress
Difficulty *math.HexOrDecimal256 Difficulty *math.HexOrDecimal256
Random *math.HexOrDecimal256 Random *math.HexOrDecimal256
ParentDifficulty *math.HexOrDecimal256 ParentDifficulty *math.HexOrDecimal256
ParentBaseFee *math.HexOrDecimal256 ParentBaseFee *math.HexOrDecimal256
ParentGasUsed math.HexOrDecimal64 ParentGasUsed math.HexOrDecimal64
ParentGasLimit math.HexOrDecimal64 ParentGasLimit math.HexOrDecimal64
GasLimit math.HexOrDecimal64 GasLimit math.HexOrDecimal64
Number math.HexOrDecimal64 Number math.HexOrDecimal64
Timestamp math.HexOrDecimal64 Timestamp math.HexOrDecimal64
ParentTimestamp math.HexOrDecimal64 ParentTimestamp math.HexOrDecimal64
BaseFee *math.HexOrDecimal256 BaseFee *math.HexOrDecimal256
ExcessBlobGas *math.HexOrDecimal64
ParentExcessBlobGas *math.HexOrDecimal64
ParentBlobGasUsed *math.HexOrDecimal64
} }
type rejectedTx struct { type rejectedTx struct {
@ -129,7 +137,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
var ( var (
statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre) statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre)
signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number)) signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp)
gaspool = new(core.GasPool) gaspool = new(core.GasPool)
blockHash = common.Hash{0x13, 0x37} blockHash = common.Hash{0x13, 0x37}
rejectedTxs []*rejectedTx rejectedTxs []*rejectedTx
@ -159,6 +167,19 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
rnd := common.BigToHash(pre.Env.Random) rnd := common.BigToHash(pre.Env.Random)
vmContext.Random = &rnd vmContext.Random = &rnd
} }
// If excessBlobGas is defined, add it to the vmContext.
if pre.Env.ExcessBlobGas != nil {
vmContext.ExcessBlobGas = pre.Env.ExcessBlobGas
} else {
// If it is not explicitly defined, but we have the parent values, we try
// to calculate it ourselves.
parentExcessBlobGas := pre.Env.ParentExcessBlobGas
parentBlobGasUsed := pre.Env.ParentBlobGasUsed
if parentExcessBlobGas != nil && parentBlobGasUsed != nil {
excessBlobGas := eip4844.CalcExcessBlobGas(*parentExcessBlobGas, *parentBlobGasUsed)
vmContext.ExcessBlobGas = &excessBlobGas
}
}
// If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's // If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's
// done in StateProcessor.Process(block, ...), right before transactions are applied. // done in StateProcessor.Process(block, ...), right before transactions are applied.
if chainConfig.DAOForkSupport && if chainConfig.DAOForkSupport &&
@ -166,8 +187,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 { chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 {
misc.ApplyDAOHardFork(statedb) misc.ApplyDAOHardFork(statedb)
} }
var blobGasUsed uint64
for i, tx := range txs { for i, tx := range txs {
if tx.Type() == types.BlobTxType && vmContext.ExcessBlobGas == nil {
errMsg := "blob tx used but field env.ExcessBlobGas missing"
log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", errMsg)
rejectedTxs = append(rejectedTxs, &rejectedTx{i, errMsg})
continue
}
msg, err := core.TransactionToMessage(tx, signer, pre.Env.BaseFee) msg, err := core.TransactionToMessage(tx, signer, pre.Env.BaseFee)
if err != nil { if err != nil {
log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err) log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err)
@ -204,7 +231,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
continue continue
} }
if tx.Type() == types.BlobTxType {
blobGasUsed += params.BlobTxBlobGasPerBlob
}
includedTxs = append(includedTxs, tx) includedTxs = append(includedTxs, tx)
if hashError != nil { if hashError != nil {
@ -258,7 +287,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
if miningReward >= 0 { if miningReward >= 0 {
// Add mining reward. The mining reward may be `0`, which only makes a difference in the cases // Add mining reward. The mining reward may be `0`, which only makes a difference in the cases
// where // where
// - the coinbase suicided, or // - the coinbase self-destructed, or
// - there are only 'bad' transactions, which aren't executed. In those cases, // - there are only 'bad' transactions, which aren't executed. In those cases,
// the coinbase gets no txfee, so isn't created, and thus needs to be touched // the coinbase gets no txfee, so isn't created, and thus needs to be touched
var ( var (
@ -287,9 +316,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
statedb.AddBalance(w.Address, amount) statedb.AddBalance(w.Address, amount)
} }
// Commit block // Commit block
root, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber)) root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber))
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Could not commit state: %v", err)
return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err)) return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err))
} }
@ -310,14 +338,22 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
h := types.DeriveSha(types.Withdrawals(pre.Env.Withdrawals), trie.NewStackTrie(nil)) h := types.DeriveSha(types.Withdrawals(pre.Env.Withdrawals), trie.NewStackTrie(nil))
execRs.WithdrawalsRoot = &h execRs.WithdrawalsRoot = &h
} }
if vmContext.ExcessBlobGas != nil {
execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(vmContext.ExcessBlobGas)
execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed)
}
// Re-create statedb instance with new root upon the updated database
// for accessing latest states.
statedb, err = state.New(root, statedb.Database(), nil)
if err != nil {
return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err))
}
return statedb, execRs, nil return statedb, execRs, nil
} }
func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB { func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB {
sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true})
statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
statedb, _ := state.New(common.Hash{}, sdb, nil)
for addr, a := range accounts { for addr, a := range accounts {
statedb.SetCode(addr, a.Code) statedb.SetCode(addr, a.Code)
statedb.SetNonce(addr, a.Nonce) statedb.SetNonce(addr, a.Nonce)
@ -328,7 +364,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB
} }
} }
// Commit and re-open to start with a clean state. // Commit and re-open to start with a clean state.
root, _ := statedb.Commit(false) root, _ := statedb.Commit(0, false)
statedb, _ = state.New(root, sdb, nil) statedb, _ = state.New(root, sdb, nil)
return statedb return statedb

View file

@ -126,19 +126,6 @@ var (
Name: "seal.clique", Name: "seal.clique",
Usage: "Seal block with Clique. `stdin` or file name of where to find the Clique sealing data.", Usage: "Seal block with Clique. `stdin` or file name of where to find the Clique sealing data.",
} }
SealEthashFlag = &cli.BoolFlag{
Name: "seal.ethash",
Usage: "Seal block with ethash.",
}
SealEthashDirFlag = &cli.StringFlag{
Name: "seal.ethash.dir",
Usage: "Path to ethash DAG. If none exists, a new DAG will be generated.",
}
SealEthashModeFlag = &cli.StringFlag{
Name: "seal.ethash.mode",
Usage: "Defines the type and amount of PoW verification an ethash engine makes.",
Value: "normal",
}
RewardFlag = &cli.Int64Flag{ RewardFlag = &cli.Int64Flag{
Name: "state.reward", Name: "state.reward",
Usage: "Mining reward. Set to -1 to disable", Usage: "Mining reward. Set to -1 to disable",

View file

@ -17,22 +17,25 @@ var _ = (*stEnvMarshaling)(nil)
// MarshalJSON marshals as JSON. // MarshalJSON marshals as JSON.
func (s stEnv) MarshalJSON() ([]byte, error) { func (s stEnv) MarshalJSON() ([]byte, error) {
type stEnv struct { type stEnv struct {
Coinbase common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"` Coinbase common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"`
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"` Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"`
Random *math.HexOrDecimal256 `json:"currentRandom"` Random *math.HexOrDecimal256 `json:"currentRandom"`
ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"` ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"`
ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"` ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"`
ParentGasUsed math.HexOrDecimal64 `json:"parentGasUsed,omitempty"` ParentGasUsed math.HexOrDecimal64 `json:"parentGasUsed,omitempty"`
ParentGasLimit math.HexOrDecimal64 `json:"parentGasLimit,omitempty"` ParentGasLimit math.HexOrDecimal64 `json:"parentGasLimit,omitempty"`
GasLimit math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"` GasLimit math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"`
Number math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"` Number math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"`
Timestamp math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"` Timestamp math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"`
ParentTimestamp math.HexOrDecimal64 `json:"parentTimestamp,omitempty"` ParentTimestamp math.HexOrDecimal64 `json:"parentTimestamp,omitempty"`
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
Ommers []ommer `json:"ommers,omitempty"` Ommers []ommer `json:"ommers,omitempty"`
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
ParentUncleHash common.Hash `json:"parentUncleHash"` ParentUncleHash common.Hash `json:"parentUncleHash"`
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas,omitempty"`
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
} }
var enc stEnv var enc stEnv
@ -52,29 +55,38 @@ func (s stEnv) MarshalJSON() ([]byte, error) {
enc.Withdrawals = s.Withdrawals enc.Withdrawals = s.Withdrawals
enc.BaseFee = (*math.HexOrDecimal256)(s.BaseFee) enc.BaseFee = (*math.HexOrDecimal256)(s.BaseFee)
enc.ParentUncleHash = s.ParentUncleHash enc.ParentUncleHash = s.ParentUncleHash
<<<<<<< HEAD
=======
enc.ExcessBlobGas = (*math.HexOrDecimal64)(s.ExcessBlobGas)
enc.ParentExcessBlobGas = (*math.HexOrDecimal64)(s.ParentExcessBlobGas)
enc.ParentBlobGasUsed = (*math.HexOrDecimal64)(s.ParentBlobGasUsed)
>>>>>>> bed84606583893fdb698cc1b5058cc47b4dbd837
return json.Marshal(&enc) return json.Marshal(&enc)
} }
// UnmarshalJSON unmarshals from JSON. // UnmarshalJSON unmarshals from JSON.
func (s *stEnv) UnmarshalJSON(input []byte) error { func (s *stEnv) UnmarshalJSON(input []byte) error {
type stEnv struct { type stEnv struct {
Coinbase *common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"` Coinbase *common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"`
Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"` Difficulty *math.HexOrDecimal256 `json:"currentDifficulty"`
Random *math.HexOrDecimal256 `json:"currentRandom"` Random *math.HexOrDecimal256 `json:"currentRandom"`
ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"` ParentDifficulty *math.HexOrDecimal256 `json:"parentDifficulty"`
ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"` ParentBaseFee *math.HexOrDecimal256 `json:"parentBaseFee,omitempty"`
ParentGasUsed *math.HexOrDecimal64 `json:"parentGasUsed,omitempty"` ParentGasUsed *math.HexOrDecimal64 `json:"parentGasUsed,omitempty"`
ParentGasLimit *math.HexOrDecimal64 `json:"parentGasLimit,omitempty"` ParentGasLimit *math.HexOrDecimal64 `json:"parentGasLimit,omitempty"`
GasLimit *math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"` GasLimit *math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"`
Number *math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"` Number *math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"`
Timestamp *math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"` Timestamp *math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"`
ParentTimestamp *math.HexOrDecimal64 `json:"parentTimestamp,omitempty"` ParentTimestamp *math.HexOrDecimal64 `json:"parentTimestamp,omitempty"`
BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
Ommers []ommer `json:"ommers,omitempty"` Ommers []ommer `json:"ommers,omitempty"`
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"`
ParentUncleHash *common.Hash `json:"parentUncleHash"` ParentUncleHash *common.Hash `json:"parentUncleHash"`
ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas,omitempty"`
ParentExcessBlobGas *math.HexOrDecimal64 `json:"parentExcessBlobGas,omitempty"`
ParentBlobGasUsed *math.HexOrDecimal64 `json:"parentBlobGasUsed,omitempty"`
} }
var dec stEnv var dec stEnv
@ -151,6 +163,18 @@ func (s *stEnv) UnmarshalJSON(input []byte) error {
if dec.ParentUncleHash != nil { if dec.ParentUncleHash != nil {
s.ParentUncleHash = *dec.ParentUncleHash s.ParentUncleHash = *dec.ParentUncleHash
} }
<<<<<<< HEAD
=======
if dec.ExcessBlobGas != nil {
s.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas)
}
if dec.ParentExcessBlobGas != nil {
s.ParentExcessBlobGas = (*uint64)(dec.ParentExcessBlobGas)
}
if dec.ParentBlobGasUsed != nil {
s.ParentBlobGasUsed = (*uint64)(dec.ParentBlobGasUsed)
}
>>>>>>> bed84606583893fdb698cc1b5058cc47b4dbd837
return nil return nil
} }

View file

@ -122,8 +122,12 @@ func Transaction(ctx *cli.Context) error {
return NewError(ErrorIO, errors.New("only rlp supported")) return NewError(ErrorIO, errors.New("only rlp supported"))
} }
} }
<<<<<<< HEAD
signer := types.MakeSigner(chainConfig, new(big.Int)) signer := types.MakeSigner(chainConfig, new(big.Int))
=======
signer := types.MakeSigner(chainConfig, new(big.Int), 0)
>>>>>>> bed84606583893fdb698cc1b5058cc47b4dbd837
// We now have the transactions in 'body', which is supposed to be an // We now have the transactions in 'body', which is supposed to be an
// rlp list of transactions // rlp list of transactions
it, err := rlp.NewListIterator([]byte(body)) it, err := rlp.NewListIterator([]byte(body))
@ -157,7 +161,7 @@ func Transaction(ctx *cli.Context) error {
} }
// Check intrinsic gas // Check intrinsic gas
if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil,
chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(0)); err != nil { chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int), 0)); err != nil {
r.Error = err r.Error = err
results = append(results, r) results = append(results, r)
@ -192,7 +196,7 @@ func Transaction(ctx *cli.Context) error {
} }
// TODO marcello double check // TODO marcello double check
// Check whether the init code size has been exceeded. // Check whether the init code size has been exceeded.
if chainConfig.IsShanghai(0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { if chainConfig.IsShanghai(new(big.Int), 0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
r.Error = errors.New("max initcode size exceeded") r.Error = errors.New("max initcode size exceeded")
} }

View file

@ -30,7 +30,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
@ -264,7 +264,7 @@ func Transition(ctx *cli.Context) error {
} }
} }
// We may have to sign the transactions. // We may have to sign the transactions.
signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number))) signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number)), prestate.Env.Timestamp)
if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil { if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil {
return NewError(ErrorJson, fmt.Errorf("failed signing transactions: %v", err)) return NewError(ErrorJson, fmt.Errorf("failed signing transactions: %v", err))
@ -280,13 +280,17 @@ func Transition(ctx *cli.Context) error {
GasUsed: prestate.Env.ParentGasUsed, GasUsed: prestate.Env.ParentGasUsed,
GasLimit: prestate.Env.ParentGasLimit, GasLimit: prestate.Env.ParentGasLimit,
} }
prestate.Env.BaseFee = misc.CalcBaseFee(chainConfig, parent) prestate.Env.BaseFee = eip1559.CalcBaseFee(chainConfig, parent)
} else { } else {
return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section"))
} }
} }
<<<<<<< HEAD
// TODO marcello double check // TODO marcello double check
if chainConfig.IsShanghai(prestate.Env.Number) && prestate.Env.Withdrawals == nil { if chainConfig.IsShanghai(prestate.Env.Number) && prestate.Env.Withdrawals == nil {
=======
if chainConfig.IsShanghai(big.NewInt(int64(prestate.Env.Number)), prestate.Env.Timestamp) && prestate.Env.Withdrawals == nil {
>>>>>>> bed84606583893fdb698cc1b5058cc47b4dbd837
return NewError(ErrorConfig, errors.New("Shanghai config but missing 'withdrawals' in env section")) return NewError(ErrorConfig, errors.New("Shanghai config but missing 'withdrawals' in env section"))
} }
@ -431,7 +435,10 @@ type Alloc map[common.Address]core.GenesisAccount
func (g Alloc) OnRoot(common.Hash) {} func (g Alloc) OnRoot(common.Hash) {}
func (g Alloc) OnAccount(addr common.Address, dumpAccount state.DumpAccount) { func (g Alloc) OnAccount(addr *common.Address, dumpAccount state.DumpAccount) {
if addr == nil {
return
}
balance, _ := new(big.Int).SetString(dumpAccount.Balance, 10) balance, _ := new(big.Int).SetString(dumpAccount.Balance, 10)
var storage map[common.Hash]common.Hash var storage map[common.Hash]common.Hash
@ -448,7 +455,7 @@ func (g Alloc) OnAccount(addr common.Address, dumpAccount state.DumpAccount) {
Balance: balance, Balance: balance,
Nonce: dumpAccount.Nonce, Nonce: dumpAccount.Nonce,
} }
g[addr] = genesisAccount g[*addr] = genesisAccount
} }
// saveFile marshals the object to the given file // saveFile marshals the object to the given file

View file

@ -180,9 +180,6 @@ var blockBuilderCommand = &cli.Command{
t8ntool.InputWithdrawalsFlag, t8ntool.InputWithdrawalsFlag,
t8ntool.InputTxsRlpFlag, t8ntool.InputTxsRlpFlag,
t8ntool.SealCliqueFlag, t8ntool.SealCliqueFlag,
t8ntool.SealEthashFlag,
t8ntool.SealEthashDirFlag,
t8ntool.SealEthashModeFlag,
t8ntool.VerbosityFlag, t8ntool.VerbosityFlag,
}, },
} }

View file

@ -36,6 +36,7 @@ import (
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/core/vm/runtime" "github.com/ethereum/go-ethereum/core/vm/runtime"
"github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/eth/tracers/logger"
@ -135,6 +136,7 @@ func runCmd(ctx *cli.Context) error {
receiver = common.BytesToAddress([]byte("receiver")) receiver = common.BytesToAddress([]byte("receiver"))
genesisConfig *core.Genesis genesisConfig *core.Genesis
preimages = ctx.Bool(DumpFlag.Name) preimages = ctx.Bool(DumpFlag.Name)
blobHashes []common.Hash // TODO (MariusVanDerWijden) implement blob hashes in state tests
) )
if ctx.Bool(MachineFlag.Name) { if ctx.Bool(MachineFlag.Name) {
@ -156,7 +158,7 @@ func runCmd(ctx *cli.Context) error {
chainConfig = gen.Config chainConfig = gen.Config
} else { } else {
sdb := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: preimages}) sdb := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), &trie.Config{Preimages: preimages})
statedb, _ = state.New(common.Hash{}, sdb, nil) statedb, _ = state.New(types.EmptyRootHash, sdb, nil)
genesisConfig = new(core.Genesis) genesisConfig = new(core.Genesis)
} }
@ -236,6 +238,7 @@ func runCmd(ctx *cli.Context) error {
Time: genesisConfig.Timestamp, Time: genesisConfig.Timestamp,
Coinbase: genesisConfig.Coinbase, Coinbase: genesisConfig.Coinbase,
BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), BlockNumber: new(big.Int).SetUint64(genesisConfig.Number),
BlobHashes: blobHashes,
EVMConfig: vm.Config{ EVMConfig: vm.Config{
Tracer: tracer, Tracer: tracer,
}, },
@ -305,8 +308,7 @@ func runCmd(ctx *cli.Context) error {
output, leftOverGas, stats, err := timedExec(bench, execFunc) output, leftOverGas, stats, err := timedExec(bench, execFunc)
if ctx.Bool(DumpFlag.Name) { if ctx.Bool(DumpFlag.Name) {
statedb.Commit(true) statedb.Commit(genesisConfig.Number, true)
statedb.IntermediateRoot(true)
fmt.Println(string(statedb.Dump(nil))) fmt.Println(string(statedb.Dump(nil)))
} }

View file

@ -17,8 +17,8 @@
package main package main
import ( import (
"bufio"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"os" "os"
@ -35,7 +35,7 @@ import (
var stateTestCommand = &cli.Command{ var stateTestCommand = &cli.Command{
Action: stateTestCmd, Action: stateTestCmd,
Name: "statetest", Name: "statetest",
Usage: "executes the given state tests", Usage: "Executes the given state tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution).",
ArgsUsage: "<file>", ArgsUsage: "<file>",
} }
@ -51,9 +51,6 @@ type StatetestResult struct {
} }
func stateTestCmd(ctx *cli.Context) error { func stateTestCmd(ctx *cli.Context) error {
if len(ctx.Args().First()) == 0 {
return errors.New("path-to-test argument required")
}
// Configure the go-ethereum logger // Configure the go-ethereum logger
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name)))
@ -66,37 +63,44 @@ func stateTestCmd(ctx *cli.Context) error {
DisableStorage: ctx.Bool(DisableStorageFlag.Name), DisableStorage: ctx.Bool(DisableStorageFlag.Name),
EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name), EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
} }
var cfg vm.Config
var (
tracer vm.EVMLogger
debugger *logger.StructLogger
)
switch { switch {
case ctx.Bool(MachineFlag.Name): case ctx.Bool(MachineFlag.Name):
tracer = logger.NewJSONLogger(config, os.Stderr) cfg.Tracer = logger.NewJSONLogger(config, os.Stderr)
case ctx.Bool(DebugFlag.Name): case ctx.Bool(DebugFlag.Name):
debugger = logger.NewStructLogger(config) cfg.Tracer = logger.NewStructLogger(config)
tracer = debugger
default:
debugger = logger.NewStructLogger(config)
} }
// Load the test content from the input file // Load the test content from the input file
src, err := os.ReadFile(ctx.Args().First()) if len(ctx.Args().First()) != 0 {
return runStateTest(ctx.Args().First(), cfg, ctx.Bool(MachineFlag.Name), ctx.Bool(DumpFlag.Name))
}
// Read filenames from stdin and execute back-to-back
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
fname := scanner.Text()
if len(fname) == 0 {
return nil
}
if err := runStateTest(fname, cfg, ctx.Bool(MachineFlag.Name), ctx.Bool(DumpFlag.Name)); err != nil {
return err
}
}
return nil
}
// runStateTest loads the state-test given by fname, and executes the test.
func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error {
src, err := os.ReadFile(fname)
if err != nil { if err != nil {
return err return err
} }
var tests map[string]tests.StateTest var tests map[string]tests.StateTest
if err = json.Unmarshal(src, &tests); err != nil { if err := json.Unmarshal(src, &tests); err != nil {
return err return err
} }
// Iterate over all the tests, run them and aggregate the results // Iterate over all the tests, run them and aggregate the results
cfg := vm.Config{
Tracer: tracer,
}
results := make([]StatetestResult, 0, len(tests)) results := make([]StatetestResult, 0, len(tests))
for key, test := range tests { for key, test := range tests {
@ -108,8 +112,7 @@ func stateTestCmd(ctx *cli.Context) error {
if s != nil { if s != nil {
root := s.IntermediateRoot(false) root := s.IntermediateRoot(false)
result.Root = &root result.Root = &root
if jsonOut {
if ctx.Bool(MachineFlag.Name) {
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
} }
} }
@ -117,22 +120,14 @@ func stateTestCmd(ctx *cli.Context) error {
if err != nil { if err != nil {
// Test failed, mark as so and dump any state to aid debugging // Test failed, mark as so and dump any state to aid debugging
result.Pass, result.Error = false, err.Error() result.Pass, result.Error = false, err.Error()
if dump && s != nil {
if ctx.Bool(DumpFlag.Name) && s != nil { s, _ = state.New(*result.Root, s.Database(), nil)
dump := s.RawDump(nil) dump := s.RawDump(nil)
result.State = &dump result.State = &dump
} }
} }
results = append(results, *result) results = append(results, *result)
// Print any structured logs collected
if ctx.Bool(DebugFlag.Name) {
if debugger != nil {
fmt.Fprintln(os.Stderr, "#### TRACE ####")
logger.WriteTrace(os.Stderr, debugger.StructLogs())
}
}
} }
} }

View file

@ -271,6 +271,14 @@ func TestT8n(t *testing.T) {
output: t8nOutput{alloc: true, result: true}, output: t8nOutput{alloc: true, result: true},
expOut: "exp.json", expOut: "exp.json",
}, },
{ // Cancun tests
base: "./testdata/28",
input: t8nInput{
"alloc.json", "txs.rlp", "env.json", "Cancun", "",
},
output: t8nOutput{alloc: true, result: true},
expOut: "exp.json",
},
} { } {
args := []string{"t8n"} args := []string{"t8n"}
args = append(args, tc.output.get()...) args = append(args, tc.output.get()...)
@ -290,7 +298,8 @@ func TestT8n(t *testing.T) {
tt.Run("evm-test", args...) tt.Run("evm-test", args...)
// Compare the expected output, if provided // Compare the expected output, if provided
if tc.expOut != "" { if tc.expOut != "" {
want, err := os.ReadFile(fmt.Sprintf("%v/%v", tc.base, tc.expOut)) file := fmt.Sprintf("%v/%v", tc.base, tc.expOut)
want, err := os.ReadFile(file)
if err != nil { if err != nil {
t.Fatalf("test %d: could not read expected output: %v", i, err) t.Fatalf("test %d: could not read expected output: %v", i, err)
} }
@ -300,9 +309,9 @@ func TestT8n(t *testing.T) {
ok, err := cmpJson(have, want) ok, err := cmpJson(have, want)
switch { switch {
case err != nil: case err != nil:
t.Fatalf("test %d, json parsing failed: %v", i, err) t.Fatalf("test %d, file %v: json parsing failed: %v", i, file, err)
case !ok: case !ok:
t.Fatalf("test %d: output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want)) t.Fatalf("test %d, file %v: output wrong, have \n%v\nwant\n%v\n", i, file, string(have), string(want))
} }
} }

View file

@ -28,6 +28,7 @@
"transactionHash": "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673", "transactionHash": "0x0557bacce3375c98d806609b8d5043072f0b6a8bae45ae5a67a00d3a1a18d673",
"contractAddress": "0x0000000000000000000000000000000000000000", "contractAddress": "0x0000000000000000000000000000000000000000",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"effectiveGasPrice": null,
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactionIndex": "0x0" "transactionIndex": "0x0"
} }

View file

@ -16,6 +16,7 @@
"transactionHash": "0xa98a24882ea90916c6a86da650fbc6b14238e46f0af04a131ce92be897507476", "transactionHash": "0xa98a24882ea90916c6a86da650fbc6b14238e46f0af04a131ce92be897507476",
"contractAddress": "0x0000000000000000000000000000000000000000", "contractAddress": "0x0000000000000000000000000000000000000000",
"gasUsed": "0x84d0", "gasUsed": "0x84d0",
"effectiveGasPrice": null,
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactionIndex": "0x0" "transactionIndex": "0x0"
}, },
@ -29,6 +30,7 @@
"transactionHash": "0x36bad80acce7040c45fd32764b5c2b2d2e6f778669fb41791f73f546d56e739a", "transactionHash": "0x36bad80acce7040c45fd32764b5c2b2d2e6f778669fb41791f73f546d56e739a",
"contractAddress": "0x0000000000000000000000000000000000000000", "contractAddress": "0x0000000000000000000000000000000000000000",
"gasUsed": "0x84d0", "gasUsed": "0x84d0",
"effectiveGasPrice": null,
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactionIndex": "0x1" "transactionIndex": "0x1"
} }

View file

@ -1,4 +1,4 @@
## Input transactions in RLP form ## Input transactions in RLP form
This testdata folder is used to examplify how transaction input can be provided in rlp form. This testdata folder is used to exemplify how transaction input can be provided in rlp form.
Please see the README in `evm` folder for how this is performed. Please see the README in `evm` folder for how this is performed.

View file

@ -1 +1 @@
These files examplify a selfdestruct to the `0`-address. These files exemplify a selfdestruct to the `0`-address.

View file

@ -15,6 +15,7 @@
"transactionHash": "0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81", "transactionHash": "0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81",
"contractAddress": "0x0000000000000000000000000000000000000000", "contractAddress": "0x0000000000000000000000000000000000000000",
"gasUsed": "0x520b", "gasUsed": "0x520b",
"effectiveGasPrice": null,
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactionIndex": "0x0" "transactionIndex": "0x0"
} }

View file

@ -1 +1 @@
These files examplify how to sign a transaction using the pre-EIP155 scheme. These files exemplify how to sign a transaction using the pre-EIP155 scheme.

View file

@ -31,6 +31,7 @@
"transactionHash": "0x92ea4a28224d033afb20e0cc2b290d4c7c2d61f6a4800a680e4e19ac962ee941", "transactionHash": "0x92ea4a28224d033afb20e0cc2b290d4c7c2d61f6a4800a680e4e19ac962ee941",
"contractAddress": "0x0000000000000000000000000000000000000000", "contractAddress": "0x0000000000000000000000000000000000000000",
"gasUsed": "0xa861", "gasUsed": "0xa861",
"effectiveGasPrice": null,
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactionIndex": "0x0" "transactionIndex": "0x0"
}, },
@ -43,6 +44,7 @@
"transactionHash": "0x16b1d912f1d664f3f60f4e1b5f296f3c82a64a1a253117b4851d18bc03c4f1da", "transactionHash": "0x16b1d912f1d664f3f60f4e1b5f296f3c82a64a1a253117b4851d18bc03c4f1da",
"contractAddress": "0x0000000000000000000000000000000000000000", "contractAddress": "0x0000000000000000000000000000000000000000",
"gasUsed": "0x5aa5", "gasUsed": "0x5aa5",
"effectiveGasPrice": null,
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactionIndex": "0x1" "transactionIndex": "0x1"
} }

View file

@ -27,6 +27,7 @@
"transactionHash": "0x92ea4a28224d033afb20e0cc2b290d4c7c2d61f6a4800a680e4e19ac962ee941", "transactionHash": "0x92ea4a28224d033afb20e0cc2b290d4c7c2d61f6a4800a680e4e19ac962ee941",
"contractAddress": "0x0000000000000000000000000000000000000000", "contractAddress": "0x0000000000000000000000000000000000000000",
"gasUsed": "0x5208", "gasUsed": "0x5208",
"effectiveGasPrice": null,
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactionIndex": "0x0" "transactionIndex": "0x0"
} }

16
cmd/evm/testdata/28/alloc.json vendored Normal file
View file

@ -0,0 +1,16 @@
{
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x016345785d8a0000",
"code" : "0x",
"nonce" : "0x00",
"storage" : {
}
},
"0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
"balance" : "0x016345785d8a0000",
"code" : "0x60004960015500",
"nonce" : "0x00",
"storage" : {
}
}
}

22
cmd/evm/testdata/28/env.json vendored Normal file
View file

@ -0,0 +1,22 @@
{
"currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
"currentNumber" : "0x01",
"currentTimestamp" : "0x079e",
"currentGasLimit" : "0x7fffffffffffffff",
"previousHash" : "0x3a9b485972e7353edd9152712492f0c58d89ef80623686b6bf947a4a6dce6cb6",
"currentBlobGasUsed" : "0x00",
"parentTimestamp" : "0x03b6",
"parentDifficulty" : "0x00",
"parentUncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"currentRandom" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"withdrawals" : [
],
"parentBaseFee" : "0x0a",
"parentGasUsed" : "0x00",
"parentGasLimit" : "0x7fffffffffffffff",
"parentExcessBlobGas" : "0x00",
"parentBlobGasUsed" : "0x00",
"blockHashes" : {
"0" : "0x3a9b485972e7353edd9152712492f0c58d89ef80623686b6bf947a4a6dce6cb6"
}
}

47
cmd/evm/testdata/28/exp.json vendored Normal file
View file

@ -0,0 +1,47 @@
{
"alloc": {
"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": {
"balance": "0x150ca"
},
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"balance": "0x16345785d80c3a9",
"nonce": "0x1"
},
"0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
"code": "0x60004960015500",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x01a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
},
"balance": "0x16345785d8a0000"
}
},
"result": {
"stateRoot": "0xa40cb3fab01848e922a48bd24191815df9f721ad4b60376edac75161517663e8",
"txRoot": "0x4409cc4b699384ba5f8248d92b784713610c5ff9c1de51e9239da0dac76de9ce",
"receiptsRoot": "0xbff643da765981266133094092d98c81d2ac8e9a83a7bbda46c3d736f1f874ac",
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"receipts": [
{
"type": "0x3",
"root": "0x",
"status": "0x1",
"cumulativeGasUsed": "0xa865",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"logs": null,
"transactionHash": "0x7508d7139d002a4b3a26a4f12dec0d87cb46075c78bf77a38b569a133b509262",
"contractAddress": "0x0000000000000000000000000000000000000000",
"gasUsed": "0xa865",
"effectiveGasPrice": null,
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactionIndex": "0x0"
}
],
"currentDifficulty": null,
"gasUsed": "0xa865",
"currentBaseFee": "0x9",
"withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"currentExcessBlobGas": "0x0",
"currentBlobGasUsed": "0x20000"
}
}

1
cmd/evm/testdata/28/txs.rlp vendored Normal file
View file

@ -0,0 +1 @@
"0xf88bb88903f8860180026483061a8094b94f5374fce5edbc8e2a8697c15331677e6ebf0b8080c00ae1a001a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d801a025e16bb498552165016751911c3608d79000ab89dc3100776e729e6ea13091c7a03acacff7fc0cff6eda8a927dec93ca17765e1ee6cbc06c5954ce102e097c01d2"

View file

@ -28,6 +28,7 @@
"transactionHash": "0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81", "transactionHash": "0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81",
"contractAddress": "0x0000000000000000000000000000000000000000", "contractAddress": "0x0000000000000000000000000000000000000000",
"gasUsed": "0x521f", "gasUsed": "0x521f",
"effectiveGasPrice": null,
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"transactionIndex": "0x0" "transactionIndex": "0x0"
} }

View file

@ -1,2 +1,6 @@
<<<<<<< HEAD
These files examplify a transition where a transaction (executed on block 5) requests These files examplify a transition where a transaction (executed on block 5) requests
=======
These files exemplify a transition where a transaction (executed on block 5) requests
>>>>>>> bed84606583893fdb698cc1b5058cc47b4dbd837
the blockhash for block `1`. the blockhash for block `1`.

View file

@ -1,3 +1,7 @@
<<<<<<< HEAD
These files examplify a transition where a transaction (executed on block 5) requests These files examplify a transition where a transaction (executed on block 5) requests
=======
These files exemplify a transition where a transaction (executed on block 5) requests
>>>>>>> bed84606583893fdb698cc1b5058cc47b4dbd837
the blockhash for block `4`, but where the hash for that block is missing. the blockhash for block `4`, but where the hash for that block is missing.
It's expected that executing these should cause `exit` with errorcode `4`. It's expected that executing these should cause `exit` with errorcode `4`.

View file

@ -1 +1 @@
These files examplify a transition where there are no transcations, two ommers, at block `N-1` (delta 1) and `N-2` (delta 2). These files exemplify a transition where there are no transactions, two ommers, at block `N-1` (delta 1) and `N-2` (delta 2).

View file

@ -280,7 +280,7 @@ To make `t8n` apply these, the following inputs are required:
- For ethash, it is `5000000000000000000` `wei`, - For ethash, it is `5000000000000000000` `wei`,
- If this is not defined, mining rewards are not applied, - If this is not defined, mining rewards are not applied,
- A value of `0` is valid, and causes accounts to be 'touched'. - A value of `0` is valid, and causes accounts to be 'touched'.
- For each ommer, the tool needs to be given an `addres\` and a `delta`. This - For each ommer, the tool needs to be given an `address\` and a `delta`. This
is done via the `ommers` field in `env`. is done via the `ommers` field in `env`.
Note: the tool does not verify that e.g. the normal uncle rules apply, Note: the tool does not verify that e.g. the normal uncle rules apply,

View file

@ -10,9 +10,11 @@ The `faucet` is a single binary app (everything included) with all configuration
First things first, the `faucet` needs to connect to an Ethereum network, for which it needs the necessary genesis and network infos. Each of the following flags must be set: First things first, the `faucet` needs to connect to an Ethereum network, for which it needs the necessary genesis and network infos. Each of the following flags must be set:
- `--genesis` is a path to a file containing the network `genesis.json` - `-genesis` is a path to a file containing the network `genesis.json`. or using:
- `--network` is the devp2p network id used during connection - `-goerli` with the faucet with Görli network config
- `--bootnodes` is a list of `enode://` ids to join the network through - `-sepolia` with the faucet with Sepolia network config
- `-network` is the devp2p network id used during connection
- `-bootnodes` is a list of `enode://` ids to join the network through
The `faucet` will use the `les` protocol to join the configured Ethereum network and will store its data in `$HOME/.faucet` (currently not configurable). The `faucet` will use the `les` protocol to join the configured Ethereum network and will store its data in `$HOME/.faucet` (currently not configurable).

View file

@ -288,12 +288,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*enode.Node, network ui
} }
} }
// Attach to the client and retrieve and interesting metadatas // Attach to the client and retrieve and interesting metadatas
api, err := stack.Attach() api := stack.Attach()
if err != nil {
stack.Close()
return nil, err
}
client := ethclient.NewClient(api) client := ethclient.NewClient(api)
return &faucet{ return &faucet{
@ -981,6 +976,6 @@ func getGenesis(genesisFlag string, goerliFlag bool, sepoliaFlag bool, mumbaiFla
case mumbaiFlag: case mumbaiFlag:
return core.DefaultMumbaiGenesisBlock(), nil return core.DefaultMumbaiGenesisBlock(), nil
default: default:
return nil, fmt.Errorf("no genesis flag provided") return nil, errors.New("no genesis flag provided")
} }
} }

View file

@ -189,12 +189,28 @@ nodes.
} }
) )
// makeAccountManager creates an account manager with backends
func makeAccountManager(ctx *cli.Context) *accounts.Manager {
cfg := loadBaseConfig(ctx)
am := accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: cfg.Node.InsecureUnlockAllowed})
keydir, isEphemeral, err := cfg.Node.GetKeyStoreDir()
if err != nil {
utils.Fatalf("Failed to get the keystore directory: %v", err)
}
if isEphemeral {
utils.Fatalf("Can't use ephemeral directory as keystore path")
}
if err := setAccountManagerBackends(&cfg.Node, am, keydir); err != nil {
utils.Fatalf("Failed to set account manager backends: %v", err)
}
return am
}
func accountList(ctx *cli.Context) error { func accountList(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx) am := makeAccountManager(ctx)
var index int var index int
for _, wallet := range am.Wallets() {
for _, wallet := range stack.AccountManager().Wallets() {
for _, account := range wallet.Accounts() { for _, account := range wallet.Accounts() {
fmt.Printf("Account #%d: {%x} %s\n", index, account.Address, &account.URL) fmt.Printf("Account #%d: {%x} %s\n", index, account.Address, &account.URL)
@ -275,19 +291,13 @@ func ambiguousAddrRecovery(ks *keystore.KeyStore, err *keystore.AmbiguousAddrErr
// accountCreate creates a new account into the keystore defined by the CLI flags. // accountCreate creates a new account into the keystore defined by the CLI flags.
func accountCreate(ctx *cli.Context) error { func accountCreate(ctx *cli.Context) error {
cfg := gethConfig{Node: defaultNodeConfig()} cfg := loadBaseConfig(ctx)
// Load config file. keydir, isEphemeral, err := cfg.Node.GetKeyStoreDir()
if file := ctx.String(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil {
utils.Fatalf("%v", err)
}
}
utils.SetNodeConfig(ctx, &cfg.Node)
keydir, err := cfg.Node.KeyDirConfig()
if err != nil { if err != nil {
utils.Fatalf("Failed to read configuration: %v", err) utils.Fatalf("Failed to get the keystore directory: %v", err)
}
if isEphemeral {
utils.Fatalf("Can't use ephemeral directory as keystore path")
} }
scryptN := keystore.StandardScryptN scryptN := keystore.StandardScryptN
@ -323,10 +333,8 @@ func accountUpdate(ctx *cli.Context) error {
if ctx.Args().Len() == 0 { if ctx.Args().Len() == 0 {
utils.Fatalf("No accounts specified to update") utils.Fatalf("No accounts specified to update")
} }
am := makeAccountManager(ctx)
stack, _ := makeConfigNode(ctx) backends := am.Backends(keystore.KeyStoreType)
backends := stack.AccountManager().Backends(keystore.KeyStoreType)
if len(backends) == 0 { if len(backends) == 0 {
utils.Fatalf("Keystore is not available") utils.Fatalf("Keystore is not available")
} }
@ -357,15 +365,14 @@ func importWallet(ctx *cli.Context) error {
utils.Fatalf("Could not read wallet file: %v", err) utils.Fatalf("Could not read wallet file: %v", err)
} }
stack, _ := makeConfigNode(ctx) am := makeAccountManager(ctx)
passphrase := utils.GetPassPhraseWithList("", false, 0, utils.MakePasswordList(ctx)) backends := am.Backends(keystore.KeyStoreType)
backends := stack.AccountManager().Backends(keystore.KeyStoreType)
if len(backends) == 0 { if len(backends) == 0 {
utils.Fatalf("Keystore is not available") utils.Fatalf("Keystore is not available")
} }
ks := backends[0].(*keystore.KeyStore) ks := backends[0].(*keystore.KeyStore)
passphrase := utils.GetPassPhraseWithList("", false, 0, utils.MakePasswordList(ctx))
acct, err := ks.ImportPreSaleKey(keyJSON, passphrase) acct, err := ks.ImportPreSaleKey(keyJSON, passphrase)
if err != nil { if err != nil {
@ -388,16 +395,14 @@ func accountImport(ctx *cli.Context) error {
if err != nil { if err != nil {
utils.Fatalf("Failed to load the private key: %v", err) utils.Fatalf("Failed to load the private key: %v", err)
} }
am := makeAccountManager(ctx)
stack, _ := makeConfigNode(ctx) backends := am.Backends(keystore.KeyStoreType)
passphrase := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
backends := stack.AccountManager().Backends(keystore.KeyStoreType)
if len(backends) == 0 { if len(backends) == 0 {
utils.Fatalf("Keystore is not available") utils.Fatalf("Keystore is not available")
} }
ks := backends[0].(*keystore.KeyStore) ks := backends[0].(*keystore.KeyStore)
passphrase := utils.GetPassPhraseWithList("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
acct, err := ks.ImportECDSA(key, passphrase) acct, err := ks.ImportECDSA(key, passphrase)
if err != nil { if err != nil {

View file

@ -66,10 +66,7 @@ func TestRemoteDbWithHeaders(t *testing.T) {
} }
func testReceiveHeaders(t *testing.T, ln net.Listener, gethArgs ...string) { func testReceiveHeaders(t *testing.T, ln net.Listener, gethArgs ...string) {
t.Helper() var ok atomic.Uint32
var ok uint32
server := &http.Server{ server := &http.Server{
Addr: "localhost:0", Addr: "localhost:0",
Handler: &testHandler{func(w http.ResponseWriter, r *http.Request) { Handler: &testHandler{func(w http.ResponseWriter, r *http.Request) {
@ -80,15 +77,14 @@ func testReceiveHeaders(t *testing.T, ln net.Listener, gethArgs ...string) {
if have, want := r.Header.Get("second"), "two"; have != want { if have, want := r.Header.Get("second"), "two"; have != want {
t.Fatalf("missing header, have %v want %v", have, want) t.Fatalf("missing header, have %v want %v", have, want)
} }
atomic.StoreUint32(&ok, 1) ok.Store(1)
}}} }}}
//nolint:errcheck //nolint:errcheck
go server.Serve(ln) go server.Serve(ln)
defer server.Close() defer server.Close()
runGeth(t, gethArgs...).WaitExit() runGeth(t, gethArgs...).WaitExit()
if ok.Load() != 1 {
if atomic.LoadUint32(&ok) != 1 {
t.Fatal("Test fail, expected invocation to succeed") t.Fatal("Test fail, expected invocation to succeed")
} }
} }

View file

@ -279,20 +279,17 @@ func importChain(ctx *cli.Context) error {
defer db.Close() defer db.Close()
// Start periodically gathering memory profiles // Start periodically gathering memory profiles
var peakMemAlloc, peakMemSys uint64 var peakMemAlloc, peakMemSys atomic.Uint64
go func() { go func() {
stats := new(runtime.MemStats) stats := new(runtime.MemStats)
for { for {
runtime.ReadMemStats(stats) runtime.ReadMemStats(stats)
if peakMemAlloc.Load() < stats.Alloc {
if atomic.LoadUint64(&peakMemAlloc) < stats.Alloc { peakMemAlloc.Store(stats.Alloc)
atomic.StoreUint64(&peakMemAlloc, stats.Alloc)
} }
if peakMemSys.Load() < stats.Sys {
if atomic.LoadUint64(&peakMemSys) < stats.Sys { peakMemSys.Store(stats.Sys)
atomic.StoreUint64(&peakMemSys, stats.Sys)
} }
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
@ -327,8 +324,8 @@ func importChain(ctx *cli.Context) error {
mem := new(runtime.MemStats) mem := new(runtime.MemStats)
runtime.ReadMemStats(mem) runtime.ReadMemStats(mem)
fmt.Printf("Object memory: %.3f MB current, %.3f MB peak\n", float64(mem.Alloc)/1024/1024, float64(atomic.LoadUint64(&peakMemAlloc))/1024/1024) fmt.Printf("Object memory: %.3f MB current, %.3f MB peak\n", float64(mem.Alloc)/1024/1024, float64(peakMemAlloc.Load())/1024/1024)
fmt.Printf("System memory: %.3f MB current, %.3f MB peak\n", float64(mem.Sys)/1024/1024, float64(atomic.LoadUint64(&peakMemSys))/1024/1024) fmt.Printf("System memory: %.3f MB current, %.3f MB peak\n", float64(mem.Sys)/1024/1024, float64(peakMemSys.Load())/1024/1024)
fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000) fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000)
fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs)) fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs))
@ -533,7 +530,7 @@ func dump(ctx *cli.Context) error {
if conf.OnlyWithAddresses { if conf.OnlyWithAddresses {
fmt.Fprintf(os.Stderr, "If you want to include accounts with missing preimages, you need iterative output, since"+ fmt.Fprintf(os.Stderr, "If you want to include accounts with missing preimages, you need iterative output, since"+
" otherwise the accounts will overwrite each other in the resulting mapping.") " otherwise the accounts will overwrite each other in the resulting mapping.")
return fmt.Errorf("incompatible options") return errors.New("incompatible options")
} }
fmt.Println(string(state.Dump(conf))) fmt.Println(string(state.Dump(conf)))

View file

@ -24,11 +24,13 @@ import (
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/external" "github.com/ethereum/go-ethereum/accounts/external"
"github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/accounts/scwallet" "github.com/ethereum/go-ethereum/accounts/scwallet"
"github.com/ethereum/go-ethereum/accounts/usbwallet" "github.com/ethereum/go-ethereum/accounts/usbwallet"
"github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/eth/catalyst"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/internal/ethapi"
@ -94,8 +96,9 @@ func defaultNodeConfig() node.Config {
return cfg return cfg
} }
// makeConfigNode loads geth configuration and creates a blank node instance. // loadBaseConfig loads the gethConfig based on the given command line
func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { // parameters and config file.
func loadBaseConfig(ctx *cli.Context) gethConfig {
// Load defaults. // Load defaults.
cfg := gethConfig{ cfg := gethConfig{
Eth: ethconfig.Defaults, Eth: ethconfig.Defaults,
@ -120,13 +123,18 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
// Apply flags. // Apply flags.
utils.SetNodeConfig(ctx, &cfg.Node) utils.SetNodeConfig(ctx, &cfg.Node)
return cfg
}
// makeConfigNode loads geth configuration and creates a blank node instance.
func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
cfg := loadBaseConfig(ctx)
stack, err := node.New(&cfg.Node) stack, err := node.New(&cfg.Node)
if err != nil { if err != nil {
utils.Fatalf("Failed to create the protocol stack: %v", err) utils.Fatalf("Failed to create the protocol stack: %v", err)
} }
// Node doesn't by default populate account manager backends // Node doesn't by default populate account manager backends
if err := setAccountManagerBackends(stack); err != nil { if err := setAccountManagerBackends(stack.Config(), stack.AccountManager(), stack.KeyStoreDir()); err != nil {
utils.Fatalf("Failed to set account manager backends: %v", err) utils.Fatalf("Failed to set account manager backends: %v", err)
} }
@ -147,10 +155,13 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
// makeFullNode loads geth configuration and creates the Ethereum backend. // makeFullNode loads geth configuration and creates the Ethereum backend.
func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
stack, cfg := makeConfigNode(ctx) stack, cfg := makeConfigNode(ctx)
// TODO marcello double check if ctx.IsSet(utils.OverrideCancun.Name) {
if ctx.IsSet(utils.OverrideShanghai.Name) { v := ctx.Uint64(utils.OverrideCancun.Name)
v := ctx.Uint64(utils.OverrideShanghai.Name) cfg.Eth.OverrideCancun = &v
cfg.Eth.OverrideShanghai = &v }
if ctx.IsSet(utils.OverrideVerkle.Name) {
v := ctx.Uint64(utils.OverrideVerkle.Name)
cfg.Eth.OverrideVerkle = &v
} }
backend, eth := utils.RegisterEthService(stack, &cfg.Eth) backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
@ -173,6 +184,21 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
utils.RegisterFullSyncTester(stack, eth, ctx.Path(utils.SyncTargetFlag.Name)) utils.RegisterFullSyncTester(stack, eth, ctx.Path(utils.SyncTargetFlag.Name))
} }
// Start the dev mode if requested, or launch the engine API for
// interacting with external consensus client.
if ctx.IsSet(utils.DeveloperFlag.Name) {
simBeacon, err := catalyst.NewSimulatedBeacon(ctx.Uint64(utils.DeveloperPeriodFlag.Name), eth)
if err != nil {
utils.Fatalf("failed to register dev mode catalyst service: %v", err)
}
catalyst.RegisterSimulatedBeaconAPIs(stack, simBeacon)
stack.RegisterLifecycle(simBeacon)
} else if cfg.Eth.SyncMode != downloader.LightSync {
err := catalyst.Register(stack, eth)
if err != nil {
utils.Fatalf("failed to register catalyst service: %v", err)
}
}
return stack, backend return stack, backend
} }
@ -257,15 +283,16 @@ func deprecated(field string) bool {
return true return true
case "ethconfig.Config.EWASMInterpreter": case "ethconfig.Config.EWASMInterpreter":
return true return true
case "ethconfig.Config.TrieCleanCacheJournal":
return true
case "ethconfig.Config.TrieCleanCacheRejournal":
return true
default: default:
return false return false
} }
} }
func setAccountManagerBackends(stack *node.Node) error { func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error {
conf := stack.Config()
am := stack.AccountManager()
keydir := stack.KeyStoreDir()
scryptN := keystore.StandardScryptN scryptN := keystore.StandardScryptN
scryptP := keystore.StandardScryptP scryptP := keystore.StandardScryptP
@ -277,9 +304,8 @@ func setAccountManagerBackends(stack *node.Node) error {
// Assemble the supported backends // Assemble the supported backends
if len(conf.ExternalSigner) > 0 { if len(conf.ExternalSigner) > 0 {
log.Info("Using external signer", "url", conf.ExternalSigner) log.Info("Using external signer", "url", conf.ExternalSigner)
if extBackend, err := external.NewExternalBackend(conf.ExternalSigner); err == nil {
if extapi, err := external.NewExternalBackend(conf.ExternalSigner); err == nil { am.AddBackend(extBackend)
am.AddBackend(extapi)
return nil return nil
} else { } else {
return fmt.Errorf("error connecting to external signer: %v", err) return fmt.Errorf("error connecting to external signer: %v", err)

View file

@ -80,11 +80,7 @@ func localConsole(ctx *cli.Context) error {
defer stack.Close() defer stack.Close()
// Attach to the newly started node and create the JavaScript console. // Attach to the newly started node and create the JavaScript console.
client, err := stack.Attach() client := stack.Attach()
if err != nil {
return fmt.Errorf("failed to attach to the inproc geth: %v", err)
}
config := console.Config{ config := console.Config{
DataDir: utils.MakeDataDir(ctx), DataDir: utils.MakeDataDir(ctx),
DocRoot: ctx.String(utils.JSpathFlag.Name), DocRoot: ctx.String(utils.JSpathFlag.Name),

View file

@ -118,7 +118,7 @@ func TestAttachWelcome(t *testing.T) {
waitForEndpoint(t, endpoint, 3*time.Second) waitForEndpoint(t, endpoint, 3*time.Second)
testAttachWelcome(t, geth, endpoint, httpAPIs) testAttachWelcome(t, geth, endpoint, httpAPIs)
}) })
geth.ExpectExit() geth.Kill()
} }
func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) { func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {

Some files were not shown because too many files have changed in this diff Show more