Merge branch 'extended-tracer' into firehose-fh3.0

# Conflicts:
#	go.mod
#	go.sum
This commit is contained in:
Matthieu Vachon 2024-01-15 12:40:19 -05:00
commit 306a1fca64
137 changed files with 2313 additions and 5774 deletions

23
.github/workflows/go.yml vendored Normal file
View file

@ -0,0 +1,23 @@
name: i386 linux tests
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
jobs:
build:
runs-on: self-hosted
steps:
- uses: actions/checkout@v2
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.21.4
- name: Run tests
run: go test ./...
env:
GOOS: linux
GOARCH: 386

View file

@ -120,6 +120,7 @@ var methods = map[string]Method{
} }
func TestReader(t *testing.T) { func TestReader(t *testing.T) {
t.Parallel()
abi := ABI{ abi := ABI{
Methods: methods, Methods: methods,
} }
@ -151,6 +152,7 @@ func TestReader(t *testing.T) {
} }
func TestInvalidABI(t *testing.T) { func TestInvalidABI(t *testing.T) {
t.Parallel()
json := `[{ "type" : "function", "name" : "", "constant" : fals }]` json := `[{ "type" : "function", "name" : "", "constant" : fals }]`
_, err := JSON(strings.NewReader(json)) _, err := JSON(strings.NewReader(json))
if err == nil { if err == nil {
@ -170,6 +172,7 @@ func TestInvalidABI(t *testing.T) {
// constructor(uint256 a, uint256 b) public{} // constructor(uint256 a, uint256 b) public{}
// } // }
func TestConstructor(t *testing.T) { func TestConstructor(t *testing.T) {
t.Parallel()
json := `[{ "inputs": [{"internalType": "uint256","name": "a","type": "uint256" },{ "internalType": "uint256","name": "b","type": "uint256"}],"stateMutability": "nonpayable","type": "constructor"}]` json := `[{ "inputs": [{"internalType": "uint256","name": "a","type": "uint256" },{ "internalType": "uint256","name": "b","type": "uint256"}],"stateMutability": "nonpayable","type": "constructor"}]`
method := NewMethod("", "", Constructor, "nonpayable", false, false, []Argument{{"a", Uint256, false}, {"b", Uint256, false}}, nil) method := NewMethod("", "", Constructor, "nonpayable", false, false, []Argument{{"a", Uint256, false}, {"b", Uint256, false}}, nil)
// Test from JSON // Test from JSON
@ -199,6 +202,7 @@ func TestConstructor(t *testing.T) {
} }
func TestTestNumbers(t *testing.T) { func TestTestNumbers(t *testing.T) {
t.Parallel()
abi, err := JSON(strings.NewReader(jsondata)) abi, err := JSON(strings.NewReader(jsondata))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -236,6 +240,7 @@ func TestTestNumbers(t *testing.T) {
} }
func TestMethodSignature(t *testing.T) { func TestMethodSignature(t *testing.T) {
t.Parallel()
m := NewMethod("foo", "foo", Function, "", false, false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil) m := NewMethod("foo", "foo", Function, "", false, false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil)
exp := "foo(string,string)" exp := "foo(string,string)"
if m.Sig != exp { if m.Sig != exp {
@ -274,6 +279,7 @@ func TestMethodSignature(t *testing.T) {
} }
func TestOverloadedMethodSignature(t *testing.T) { func TestOverloadedMethodSignature(t *testing.T) {
t.Parallel()
json := `[{"constant":true,"inputs":[{"name":"i","type":"uint256"},{"name":"j","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"i","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"}],"name":"bar","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"},{"indexed":false,"name":"j","type":"uint256"}],"name":"bar","type":"event"}]` json := `[{"constant":true,"inputs":[{"name":"i","type":"uint256"},{"name":"j","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"i","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"}],"name":"bar","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"},{"indexed":false,"name":"j","type":"uint256"}],"name":"bar","type":"event"}]`
abi, err := JSON(strings.NewReader(json)) abi, err := JSON(strings.NewReader(json))
if err != nil { if err != nil {
@ -297,6 +303,7 @@ func TestOverloadedMethodSignature(t *testing.T) {
} }
func TestCustomErrors(t *testing.T) { func TestCustomErrors(t *testing.T) {
t.Parallel()
json := `[{ "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ],"name": "MyError", "type": "error"} ]` json := `[{ "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ],"name": "MyError", "type": "error"} ]`
abi, err := JSON(strings.NewReader(json)) abi, err := JSON(strings.NewReader(json))
if err != nil { if err != nil {
@ -311,6 +318,7 @@ func TestCustomErrors(t *testing.T) {
} }
func TestMultiPack(t *testing.T) { func TestMultiPack(t *testing.T) {
t.Parallel()
abi, err := JSON(strings.NewReader(jsondata)) abi, err := JSON(strings.NewReader(jsondata))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -348,6 +356,7 @@ func ExampleJSON() {
} }
func TestInputVariableInputLength(t *testing.T) { func TestInputVariableInputLength(t *testing.T) {
t.Parallel()
const definition = `[ const definition = `[
{ "type" : "function", "name" : "strOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" } ] }, { "type" : "function", "name" : "strOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" } ] },
{ "type" : "function", "name" : "bytesOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "bytes" } ] }, { "type" : "function", "name" : "bytesOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "bytes" } ] },
@ -476,6 +485,7 @@ func TestInputVariableInputLength(t *testing.T) {
} }
func TestInputFixedArrayAndVariableInputLength(t *testing.T) { func TestInputFixedArrayAndVariableInputLength(t *testing.T) {
t.Parallel()
abi, err := JSON(strings.NewReader(jsondata)) abi, err := JSON(strings.NewReader(jsondata))
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -650,6 +660,7 @@ func TestInputFixedArrayAndVariableInputLength(t *testing.T) {
} }
func TestDefaultFunctionParsing(t *testing.T) { func TestDefaultFunctionParsing(t *testing.T) {
t.Parallel()
const definition = `[{ "name" : "balance", "type" : "function" }]` const definition = `[{ "name" : "balance", "type" : "function" }]`
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
@ -663,6 +674,7 @@ func TestDefaultFunctionParsing(t *testing.T) {
} }
func TestBareEvents(t *testing.T) { func TestBareEvents(t *testing.T) {
t.Parallel()
const definition = `[ const definition = `[
{ "type" : "event", "name" : "balance" }, { "type" : "event", "name" : "balance" },
{ "type" : "event", "name" : "anon", "anonymous" : true}, { "type" : "event", "name" : "anon", "anonymous" : true},
@ -739,6 +751,7 @@ func TestBareEvents(t *testing.T) {
// //
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]} // receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
func TestUnpackEvent(t *testing.T) { func TestUnpackEvent(t *testing.T) {
t.Parallel()
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]` const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
abi, err := JSON(strings.NewReader(abiJSON)) abi, err := JSON(strings.NewReader(abiJSON))
if err != nil { if err != nil {
@ -777,6 +790,7 @@ func TestUnpackEvent(t *testing.T) {
} }
func TestUnpackEventIntoMap(t *testing.T) { func TestUnpackEventIntoMap(t *testing.T) {
t.Parallel()
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]` const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
abi, err := JSON(strings.NewReader(abiJSON)) abi, err := JSON(strings.NewReader(abiJSON))
if err != nil { if err != nil {
@ -827,6 +841,7 @@ func TestUnpackEventIntoMap(t *testing.T) {
} }
func TestUnpackMethodIntoMap(t *testing.T) { func TestUnpackMethodIntoMap(t *testing.T) {
t.Parallel()
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"send","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"get","outputs":[{"name":"hash","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"}]` const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"send","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"get","outputs":[{"name":"hash","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"}]`
abi, err := JSON(strings.NewReader(abiJSON)) abi, err := JSON(strings.NewReader(abiJSON))
if err != nil { if err != nil {
@ -877,6 +892,7 @@ func TestUnpackMethodIntoMap(t *testing.T) {
} }
func TestUnpackIntoMapNamingConflict(t *testing.T) { func TestUnpackIntoMapNamingConflict(t *testing.T) {
t.Parallel()
// Two methods have the same name // Two methods have the same name
var abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"get","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"send","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"get","outputs":[{"name":"hash","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"}]` var abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"get","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"send","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"get","outputs":[{"name":"hash","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"}]`
abi, err := JSON(strings.NewReader(abiJSON)) abi, err := JSON(strings.NewReader(abiJSON))
@ -960,6 +976,7 @@ func TestUnpackIntoMapNamingConflict(t *testing.T) {
} }
func TestABI_MethodById(t *testing.T) { func TestABI_MethodById(t *testing.T) {
t.Parallel()
abi, err := JSON(strings.NewReader(jsondata)) abi, err := JSON(strings.NewReader(jsondata))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -992,6 +1009,7 @@ func TestABI_MethodById(t *testing.T) {
} }
func TestABI_EventById(t *testing.T) { func TestABI_EventById(t *testing.T) {
t.Parallel()
tests := []struct { tests := []struct {
name string name string
json string json string
@ -1058,6 +1076,7 @@ func TestABI_EventById(t *testing.T) {
} }
func TestABI_ErrorByID(t *testing.T) { func TestABI_ErrorByID(t *testing.T) {
t.Parallel()
abi, err := JSON(strings.NewReader(`[ abi, err := JSON(strings.NewReader(`[
{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"MyError1","type":"error"}, {"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":[{"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"},
@ -1088,6 +1107,7 @@ func TestABI_ErrorByID(t *testing.T) {
// 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) {
t.Parallel()
abiJSON := `[{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"}],"name":"transfer0","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"},{"name":"customFallback","type":"string"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]` abiJSON := `[{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"}],"name":"transfer0","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"},{"name":"customFallback","type":"string"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]`
contractAbi, err := JSON(strings.NewReader(abiJSON)) contractAbi, err := JSON(strings.NewReader(abiJSON))
if err != nil { if err != nil {
@ -1117,6 +1137,7 @@ func TestDoubleDuplicateMethodNames(t *testing.T) {
// event send(); // event send();
// } // }
func TestDoubleDuplicateEventNames(t *testing.T) { func TestDoubleDuplicateEventNames(t *testing.T) {
t.Parallel()
abiJSON := `[{"anonymous": false,"inputs": [{"indexed": false,"internalType": "uint256","name": "a","type": "uint256"}],"name": "send","type": "event"},{"anonymous": false,"inputs": [],"name": "send0","type": "event"},{ "anonymous": false, "inputs": [],"name": "send","type": "event"}]` abiJSON := `[{"anonymous": false,"inputs": [{"indexed": false,"internalType": "uint256","name": "a","type": "uint256"}],"name": "send","type": "event"},{"anonymous": false,"inputs": [],"name": "send0","type": "event"},{ "anonymous": false, "inputs": [],"name": "send","type": "event"}]`
contractAbi, err := JSON(strings.NewReader(abiJSON)) contractAbi, err := JSON(strings.NewReader(abiJSON))
if err != nil { if err != nil {
@ -1144,6 +1165,7 @@ func TestDoubleDuplicateEventNames(t *testing.T) {
// event send(uint256, uint256); // event send(uint256, uint256);
// } // }
func TestUnnamedEventParam(t *testing.T) { func TestUnnamedEventParam(t *testing.T) {
t.Parallel()
abiJSON := `[{ "anonymous": false, "inputs": [{ "indexed": false,"internalType": "uint256", "name": "","type": "uint256"},{"indexed": false,"internalType": "uint256","name": "","type": "uint256"}],"name": "send","type": "event"}]` abiJSON := `[{ "anonymous": false, "inputs": [{ "indexed": false,"internalType": "uint256", "name": "","type": "uint256"},{"indexed": false,"internalType": "uint256","name": "","type": "uint256"}],"name": "send","type": "event"}]`
contractAbi, err := JSON(strings.NewReader(abiJSON)) contractAbi, err := JSON(strings.NewReader(abiJSON))
if err != nil { if err != nil {
@ -1177,7 +1199,9 @@ func TestUnpackRevert(t *testing.T) {
{"4e487b7100000000000000000000000000000000000000000000000000000000000000ff", "unknown panic code: 0xff", nil}, {"4e487b7100000000000000000000000000000000000000000000000000000000000000ff", "unknown panic code: 0xff", nil},
} }
for index, c := range cases { for index, c := range cases {
index, c := index, c
t.Run(fmt.Sprintf("case %d", index), func(t *testing.T) { t.Run(fmt.Sprintf("case %d", index), func(t *testing.T) {
t.Parallel()
got, err := UnpackRevert(common.Hex2Bytes(c.input)) got, err := UnpackRevert(common.Hex2Bytes(c.input))
if c.expectErr != nil { if c.expectErr != nil {
if err == nil { if err == nil {

View file

@ -28,6 +28,7 @@ import (
// TestReplicate can be used to replicate crashers from the fuzzing tests. // TestReplicate can be used to replicate crashers from the fuzzing tests.
// Just replace testString with the data in .quoted // Just replace testString with the data in .quoted
func TestReplicate(t *testing.T) { func TestReplicate(t *testing.T) {
t.Parallel()
//t.Skip("Test only useful for reproducing issues") //t.Skip("Test only useful for reproducing issues")
fuzzAbi([]byte("\x20\x20\x20\x20\x20\x20\x20\x20\x80\x00\x00\x00\x20\x20\x20\x20\x00")) fuzzAbi([]byte("\x20\x20\x20\x20\x20\x20\x20\x20\x80\x00\x00\x00\x20\x20\x20\x20\x00"))
//fuzzAbi([]byte("asdfasdfkadsf;lasdf;lasd;lfk")) //fuzzAbi([]byte("asdfasdfkadsf;lasdf;lasd;lfk"))

View file

@ -56,7 +56,7 @@ func NewTransactor(keyin io.Reader, passphrase string) (*TransactOpts, error) {
} }
// NewKeyStoreTransactor is a utility method to easily create a transaction signer from // NewKeyStoreTransactor is a utility method to easily create a transaction signer from
// an decrypted key from a keystore. // a decrypted key from a keystore.
// //
// Deprecated: Use NewKeyStoreTransactorWithChainID instead. // Deprecated: Use NewKeyStoreTransactorWithChainID instead.
func NewKeyStoreTransactor(keystore *keystore.KeyStore, account accounts.Account) (*TransactOpts, error) { func NewKeyStoreTransactor(keystore *keystore.KeyStore, account accounts.Account) (*TransactOpts, error) {

View file

@ -75,7 +75,7 @@ type BlockHashContractCaller interface {
// CodeAtHash returns the code of the given account in the state at the specified block hash. // CodeAtHash returns the code of the given account in the state at the specified block hash.
CodeAtHash(ctx context.Context, contract common.Address, blockHash common.Hash) ([]byte, error) CodeAtHash(ctx context.Context, contract common.Address, blockHash common.Hash) ([]byte, error)
// CallContractAtHash executes an Ethereum contract all against the state at the specified block hash. // CallContractAtHash executes an Ethereum contract call against the state at the specified block hash.
CallContractAtHash(ctx context.Context, call ethereum.CallMsg, blockHash common.Hash) ([]byte, error) CallContractAtHash(ctx context.Context, call ethereum.CallMsg, blockHash common.Hash) ([]byte, error)
} }

View file

@ -38,6 +38,7 @@ import (
) )
func TestSimulatedBackend(t *testing.T) { func TestSimulatedBackend(t *testing.T) {
t.Parallel()
var gasLimit uint64 = 8000029 var gasLimit uint64 = 8000029
key, _ := crypto.GenerateKey() // nolint: gosec key, _ := crypto.GenerateKey() // nolint: gosec
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
@ -121,6 +122,7 @@ func simTestBackend(testAddr common.Address) *SimulatedBackend {
} }
func TestNewSimulatedBackend(t *testing.T) { func TestNewSimulatedBackend(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
expectedBal := big.NewInt(10000000000000000) expectedBal := big.NewInt(10000000000000000)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
@ -142,6 +144,7 @@ func TestNewSimulatedBackend(t *testing.T) {
} }
func TestAdjustTime(t *testing.T) { func TestAdjustTime(t *testing.T) {
t.Parallel()
sim := NewSimulatedBackend( sim := NewSimulatedBackend(
core.GenesisAlloc{}, 10000000, core.GenesisAlloc{}, 10000000,
) )
@ -159,6 +162,7 @@ func TestAdjustTime(t *testing.T) {
} }
func TestNewAdjustTimeFail(t *testing.T) { func TestNewAdjustTimeFail(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
defer sim.blockchain.Stop() defer sim.blockchain.Stop()
@ -202,6 +206,7 @@ func TestNewAdjustTimeFail(t *testing.T) {
} }
func TestBalanceAt(t *testing.T) { func TestBalanceAt(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
expectedBal := big.NewInt(10000000000000000) expectedBal := big.NewInt(10000000000000000)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
@ -219,6 +224,7 @@ func TestBalanceAt(t *testing.T) {
} }
func TestBlockByHash(t *testing.T) { func TestBlockByHash(t *testing.T) {
t.Parallel()
sim := NewSimulatedBackend( sim := NewSimulatedBackend(
core.GenesisAlloc{}, 10000000, core.GenesisAlloc{}, 10000000,
) )
@ -240,6 +246,7 @@ func TestBlockByHash(t *testing.T) {
} }
func TestBlockByNumber(t *testing.T) { func TestBlockByNumber(t *testing.T) {
t.Parallel()
sim := NewSimulatedBackend( sim := NewSimulatedBackend(
core.GenesisAlloc{}, 10000000, core.GenesisAlloc{}, 10000000,
) )
@ -275,6 +282,7 @@ func TestBlockByNumber(t *testing.T) {
} }
func TestNonceAt(t *testing.T) { func TestNonceAt(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
@ -328,6 +336,7 @@ func TestNonceAt(t *testing.T) {
} }
func TestSendTransaction(t *testing.T) { func TestSendTransaction(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
@ -362,6 +371,7 @@ func TestSendTransaction(t *testing.T) {
} }
func TestTransactionByHash(t *testing.T) { func TestTransactionByHash(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := NewSimulatedBackend( sim := NewSimulatedBackend(
@ -416,6 +426,7 @@ func TestTransactionByHash(t *testing.T) {
} }
func TestEstimateGas(t *testing.T) { func TestEstimateGas(t *testing.T) {
t.Parallel()
/* /*
pragma solidity ^0.6.4; pragma solidity ^0.6.4;
contract GasEstimation { contract GasEstimation {
@ -535,6 +546,7 @@ func TestEstimateGas(t *testing.T) {
} }
func TestEstimateGasWithPrice(t *testing.T) { func TestEstimateGasWithPrice(t *testing.T) {
t.Parallel()
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
@ -625,6 +637,7 @@ func TestEstimateGasWithPrice(t *testing.T) {
} }
func TestHeaderByHash(t *testing.T) { func TestHeaderByHash(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
@ -646,6 +659,7 @@ func TestHeaderByHash(t *testing.T) {
} }
func TestHeaderByNumber(t *testing.T) { func TestHeaderByNumber(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
@ -692,6 +706,7 @@ func TestHeaderByNumber(t *testing.T) {
} }
func TestTransactionCount(t *testing.T) { func TestTransactionCount(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
@ -744,6 +759,7 @@ func TestTransactionCount(t *testing.T) {
} }
func TestTransactionInBlock(t *testing.T) { func TestTransactionInBlock(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
@ -809,6 +825,7 @@ func TestTransactionInBlock(t *testing.T) {
} }
func TestPendingNonceAt(t *testing.T) { func TestPendingNonceAt(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
@ -874,6 +891,7 @@ func TestPendingNonceAt(t *testing.T) {
} }
func TestTransactionReceipt(t *testing.T) { func TestTransactionReceipt(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
@ -908,6 +926,7 @@ func TestTransactionReceipt(t *testing.T) {
} }
func TestSuggestGasPrice(t *testing.T) { func TestSuggestGasPrice(t *testing.T) {
t.Parallel()
sim := NewSimulatedBackend( sim := NewSimulatedBackend(
core.GenesisAlloc{}, core.GenesisAlloc{},
10000000, 10000000,
@ -924,6 +943,7 @@ func TestSuggestGasPrice(t *testing.T) {
} }
func TestPendingCodeAt(t *testing.T) { func TestPendingCodeAt(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
defer sim.Close() defer sim.Close()
@ -960,6 +980,7 @@ func TestPendingCodeAt(t *testing.T) {
} }
func TestCodeAt(t *testing.T) { func TestCodeAt(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
defer sim.Close() defer sim.Close()
@ -997,6 +1018,7 @@ func TestCodeAt(t *testing.T) {
} }
func TestCodeAtHash(t *testing.T) { func TestCodeAtHash(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
defer sim.Close() defer sim.Close()
@ -1037,6 +1059,7 @@ func TestCodeAtHash(t *testing.T) {
// //
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]} // receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
func TestPendingAndCallContract(t *testing.T) { func TestPendingAndCallContract(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
defer sim.Close() defer sim.Close()
@ -1138,6 +1161,7 @@ contract Reverter {
} }
}*/ }*/
func TestCallContractRevert(t *testing.T) { func TestCallContractRevert(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
defer sim.Close() defer sim.Close()
@ -1233,6 +1257,7 @@ func TestCallContractRevert(t *testing.T) {
// Since Commit() was called 2n+1 times in total, // Since Commit() was called 2n+1 times in total,
// having a chain length of just n+1 means that a reorg occurred. // having a chain length of just n+1 means that a reorg occurred.
func TestFork(t *testing.T) { func TestFork(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
defer sim.Close() defer sim.Close()
@ -1286,6 +1311,7 @@ const callableBin = "6080604052348015600f57600080fd5b5060998061001e6000396000f3f
// 9. Re-send the transaction and mine a block. // 9. Re-send the transaction and mine a block.
// 10. Check that the event was reborn. // 10. Check that the event was reborn.
func TestForkLogsReborn(t *testing.T) { func TestForkLogsReborn(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
defer sim.Close() defer sim.Close()
@ -1359,6 +1385,7 @@ func TestForkLogsReborn(t *testing.T) {
// 5. Mine a block, Re-send the transaction and mine another one. // 5. Mine a block, Re-send the transaction and mine another one.
// 6. Check that the TX is now included in block 2. // 6. Check that the TX is now included in block 2.
func TestForkResendTx(t *testing.T) { func TestForkResendTx(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
defer sim.Close() defer sim.Close()
@ -1395,6 +1422,7 @@ func TestForkResendTx(t *testing.T) {
} }
func TestCommitReturnValue(t *testing.T) { func TestCommitReturnValue(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
defer sim.Close() defer sim.Close()
@ -1436,6 +1464,7 @@ func TestCommitReturnValue(t *testing.T) {
// TestAdjustTimeAfterFork ensures that after a fork, AdjustTime uses the pending fork // TestAdjustTimeAfterFork ensures that after a fork, AdjustTime uses the pending fork
// block's parent rather than the canonical head's parent. // block's parent rather than the canonical head's parent.
func TestAdjustTimeAfterFork(t *testing.T) { func TestAdjustTimeAfterFork(t *testing.T) {
t.Parallel()
testAddr := crypto.PubkeyToAddress(testKey.PublicKey) testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
sim := simTestBackend(testAddr) sim := simTestBackend(testAddr)
defer sim.Close() defer sim.Close()

View file

@ -135,6 +135,7 @@ func (mc *mockBlockHashCaller) CallContractAtHash(ctx context.Context, call ethe
} }
func TestPassingBlockNumber(t *testing.T) { func TestPassingBlockNumber(t *testing.T) {
t.Parallel()
mc := &mockPendingCaller{ mc := &mockPendingCaller{
mockCaller: &mockCaller{ mockCaller: &mockCaller{
codeAtBytes: []byte{1, 2, 3}, codeAtBytes: []byte{1, 2, 3},
@ -186,6 +187,7 @@ func TestPassingBlockNumber(t *testing.T) {
const hexData = "0x000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158" const hexData = "0x000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158"
func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) { func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) {
t.Parallel()
hash := crypto.Keccak256Hash([]byte("testName")) hash := crypto.Keccak256Hash([]byte("testName"))
topics := []common.Hash{ topics := []common.Hash{
crypto.Keccak256Hash([]byte("received(string,address,uint256,bytes)")), crypto.Keccak256Hash([]byte("received(string,address,uint256,bytes)")),
@ -207,6 +209,7 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) {
} }
func TestUnpackAnonymousLogIntoMap(t *testing.T) { func TestUnpackAnonymousLogIntoMap(t *testing.T) {
t.Parallel()
mockLog := newMockLog(nil, common.HexToHash("0x0")) mockLog := newMockLog(nil, common.HexToHash("0x0"))
abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]` abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]`
@ -224,6 +227,7 @@ func TestUnpackAnonymousLogIntoMap(t *testing.T) {
} }
func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) { func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) {
t.Parallel()
sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"}) sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -249,6 +253,7 @@ func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) {
} }
func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) { func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) {
t.Parallel()
arrBytes, err := rlp.EncodeToBytes([2]common.Address{common.HexToAddress("0x0"), common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2")}) arrBytes, err := rlp.EncodeToBytes([2]common.Address{common.HexToAddress("0x0"), common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2")})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -274,6 +279,7 @@ func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) {
} }
func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) { func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) {
t.Parallel()
mockAddress := common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2") mockAddress := common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2")
addrBytes := mockAddress.Bytes() addrBytes := mockAddress.Bytes()
hash := crypto.Keccak256Hash([]byte("mockFunction(address,uint)")) hash := crypto.Keccak256Hash([]byte("mockFunction(address,uint)"))
@ -300,6 +306,7 @@ func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) {
} }
func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) { func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) {
t.Parallel()
bytes := []byte{1, 2, 3, 4, 5} bytes := []byte{1, 2, 3, 4, 5}
hash := crypto.Keccak256Hash(bytes) hash := crypto.Keccak256Hash(bytes)
topics := []common.Hash{ topics := []common.Hash{
@ -322,6 +329,7 @@ func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) {
} }
func TestTransactGasFee(t *testing.T) { func TestTransactGasFee(t *testing.T) {
t.Parallel()
assert := assert.New(t) assert := assert.New(t)
// GasTipCap and GasFeeCap // GasTipCap and GasFeeCap
@ -397,6 +405,7 @@ func newMockLog(topics []common.Hash, txHash common.Hash) types.Log {
} }
func TestCall(t *testing.T) { func TestCall(t *testing.T) {
t.Parallel()
var method, methodWithArg = "something", "somethingArrrrg" var method, methodWithArg = "something", "somethingArrrrg"
tests := []struct { tests := []struct {
name, method string name, method string
@ -572,6 +581,7 @@ func TestCall(t *testing.T) {
// TestCrashers contains some strings which previously caused the abi codec to crash. // TestCrashers contains some strings which previously caused the abi codec to crash.
func TestCrashers(t *testing.T) { func TestCrashers(t *testing.T) {
t.Parallel()
abi.JSON(strings.NewReader(`[{"inputs":[{"type":"tuple[]","components":[{"type":"bool","name":"_1"}]}]}]`)) abi.JSON(strings.NewReader(`[{"inputs":[{"type":"tuple[]","components":[{"type":"bool","name":"_1"}]}]}]`))
abi.JSON(strings.NewReader(`[{"inputs":[{"type":"tuple[]","components":[{"type":"bool","name":"&"}]}]}]`)) abi.JSON(strings.NewReader(`[{"inputs":[{"type":"tuple[]","components":[{"type":"bool","name":"&"}]}]}]`))
abi.JSON(strings.NewReader(`[{"inputs":[{"type":"tuple[]","components":[{"type":"bool","name":"----"}]}]}]`)) abi.JSON(strings.NewReader(`[{"inputs":[{"type":"tuple[]","components":[{"type":"bool","name":"----"}]}]}]`))

View file

@ -363,7 +363,7 @@ func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
// parameters that are not value types i.e. arrays and structs are not // parameters that are not value types i.e. arrays and structs are not
// stored directly but instead a keccak256-hash of an encoding is stored. // stored directly but instead a keccak256-hash of an encoding is stored.
// //
// We only convert stringS and bytes to hash, still need to deal with // We only convert strings and bytes to hash, still need to deal with
// array(both fixed-size and dynamic-size) and struct. // array(both fixed-size and dynamic-size) and struct.
if bound == "string" || bound == "[]byte" { if bound == "string" || bound == "[]byte" {
bound = "common.Hash" bound = "common.Hash"

View file

@ -1677,7 +1677,7 @@ var bindTests = []struct {
} }
sim.Commit() sim.Commit()
// This test the existence of the free retreiver call for view and pure functions // This test the existence of the free retriever call for view and pure functions
if num, err := pav.PureFunc(nil); err != nil { if num, err := pav.PureFunc(nil); err != nil {
t.Fatalf("Failed to call anonymous field retriever: %v", err) t.Fatalf("Failed to call anonymous field retriever: %v", err)
} else if num.Cmp(big.NewInt(42)) != 0 { } else if num.Cmp(big.NewInt(42)) != 0 {
@ -2067,6 +2067,7 @@ var bindTests = []struct {
// Tests that packages generated by the binder can be successfully compiled and // Tests that packages generated by the binder can be successfully compiled and
// the requested tester run against it. // the requested tester run against it.
func TestGolangBindings(t *testing.T) { func TestGolangBindings(t *testing.T) {
t.Parallel()
// Skip the test if no Go command can be found // Skip the test if no Go command can be found
gocmd := runtime.GOROOT() + "/bin/go" gocmd := runtime.GOROOT() + "/bin/go"
if !common.FileExist(gocmd) { if !common.FileExist(gocmd) {

View file

@ -53,6 +53,7 @@ var waitDeployedTests = map[string]struct {
} }
func TestWaitDeployed(t *testing.T) { func TestWaitDeployed(t *testing.T) {
t.Parallel()
for name, test := range waitDeployedTests { for name, test := range waitDeployedTests {
backend := backends.NewSimulatedBackend( backend := backends.NewSimulatedBackend(
core.GenesisAlloc{ core.GenesisAlloc{
@ -100,6 +101,7 @@ func TestWaitDeployed(t *testing.T) {
} }
func TestWaitDeployedCornerCases(t *testing.T) { func TestWaitDeployedCornerCases(t *testing.T) {
t.Parallel()
backend := backends.NewSimulatedBackend( backend := backends.NewSimulatedBackend(
core.GenesisAlloc{ core.GenesisAlloc{
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)}, crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)},
@ -119,9 +121,9 @@ func TestWaitDeployedCornerCases(t *testing.T) {
defer cancel() defer cancel()
backend.SendTransaction(ctx, tx) backend.SendTransaction(ctx, tx)
backend.Commit() backend.Commit()
notContentCreation := errors.New("tx is not contract creation") notContractCreation := errors.New("tx is not contract creation")
if _, err := bind.WaitDeployed(ctx, backend, tx); err.Error() != notContentCreation.Error() { if _, err := bind.WaitDeployed(ctx, backend, tx); err.Error() != notContractCreation.Error() {
t.Errorf("error mismatch: want %q, got %q, ", notContentCreation, err) t.Errorf("error mismatch: want %q, got %q, ", notContractCreation, err)
} }
// Create a transaction that is not mined. // Create a transaction that is not mined.

View file

@ -81,6 +81,7 @@ var pledgeData1 = "00000000000000000000000000ce0d46d924cc8437c806721496599fc3ffa
var mixedCaseData1 = "00000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000000000020489e8000000000000000000000000000000000000000000000000000000000000000f4241" var mixedCaseData1 = "00000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000000000020489e8000000000000000000000000000000000000000000000000000000000000000f4241"
func TestEventId(t *testing.T) { func TestEventId(t *testing.T) {
t.Parallel()
var table = []struct { var table = []struct {
definition string definition string
expectations map[string]common.Hash expectations map[string]common.Hash
@ -112,6 +113,7 @@ func TestEventId(t *testing.T) {
} }
func TestEventString(t *testing.T) { func TestEventString(t *testing.T) {
t.Parallel()
var table = []struct { var table = []struct {
definition string definition string
expectations map[string]string expectations map[string]string
@ -146,6 +148,7 @@ func TestEventString(t *testing.T) {
// TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array. // TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array.
func TestEventMultiValueWithArrayUnpack(t *testing.T) { func TestEventMultiValueWithArrayUnpack(t *testing.T) {
t.Parallel()
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]` definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
require.NoError(t, err) require.NoError(t, err)
@ -161,6 +164,7 @@ func TestEventMultiValueWithArrayUnpack(t *testing.T) {
} }
func TestEventTupleUnpack(t *testing.T) { func TestEventTupleUnpack(t *testing.T) {
t.Parallel()
type EventTransfer struct { type EventTransfer struct {
Value *big.Int Value *big.Int
} }
@ -351,6 +355,7 @@ func unpackTestEventData(dest interface{}, hexData string, jsonEvent []byte, ass
// TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder. // TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder.
func TestEventUnpackIndexed(t *testing.T) { func TestEventUnpackIndexed(t *testing.T) {
t.Parallel()
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]` definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
type testStruct struct { type testStruct struct {
Value1 uint8 // indexed Value1 uint8 // indexed
@ -368,6 +373,7 @@ func TestEventUnpackIndexed(t *testing.T) {
// TestEventIndexedWithArrayUnpack verifies that decoder will not overflow when static array is indexed input. // TestEventIndexedWithArrayUnpack verifies that decoder will not overflow when static array is indexed input.
func TestEventIndexedWithArrayUnpack(t *testing.T) { func TestEventIndexedWithArrayUnpack(t *testing.T) {
t.Parallel()
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]` definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]`
type testStruct struct { type testStruct struct {
Value1 [2]uint8 // indexed Value1 [2]uint8 // indexed

View file

@ -35,6 +35,7 @@ const methoddata = `
]` ]`
func TestMethodString(t *testing.T) { func TestMethodString(t *testing.T) {
t.Parallel()
var table = []struct { var table = []struct {
method string method string
expectation string expectation string
@ -99,6 +100,7 @@ func TestMethodString(t *testing.T) {
} }
func TestMethodSig(t *testing.T) { func TestMethodSig(t *testing.T) {
t.Parallel()
var cases = []struct { var cases = []struct {
method string method string
expect string expect string

View file

@ -32,8 +32,11 @@ import (
// TestPack tests the general pack/unpack tests in packing_test.go // TestPack tests the general pack/unpack tests in packing_test.go
func TestPack(t *testing.T) { func TestPack(t *testing.T) {
t.Parallel()
for i, test := range packUnpackTests { for i, test := range packUnpackTests {
i, test := i, test
t.Run(strconv.Itoa(i), func(t *testing.T) { t.Run(strconv.Itoa(i), func(t *testing.T) {
t.Parallel()
encb, err := hex.DecodeString(test.packed) encb, err := hex.DecodeString(test.packed)
if err != nil { if err != nil {
t.Fatalf("invalid hex %s: %v", test.packed, err) t.Fatalf("invalid hex %s: %v", test.packed, err)
@ -57,6 +60,7 @@ func TestPack(t *testing.T) {
} }
func TestMethodPack(t *testing.T) { func TestMethodPack(t *testing.T) {
t.Parallel()
abi, err := JSON(strings.NewReader(jsondata)) abi, err := JSON(strings.NewReader(jsondata))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -177,6 +181,7 @@ func TestMethodPack(t *testing.T) {
} }
func TestPackNumber(t *testing.T) { func TestPackNumber(t *testing.T) {
t.Parallel()
tests := []struct { tests := []struct {
value reflect.Value value reflect.Value
packed []byte packed []byte

View file

@ -170,8 +170,11 @@ var reflectTests = []reflectTest{
} }
func TestReflectNameToStruct(t *testing.T) { func TestReflectNameToStruct(t *testing.T) {
t.Parallel()
for _, test := range reflectTests { for _, test := range reflectTests {
test := test
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
t.Parallel()
m, err := mapArgNamesToStructFields(test.args, reflect.ValueOf(test.struc)) m, err := mapArgNamesToStructFields(test.args, reflect.ValueOf(test.struc))
if len(test.err) > 0 { if len(test.err) > 0 {
if err == nil || err.Error() != test.err { if err == nil || err.Error() != test.err {
@ -192,6 +195,7 @@ func TestReflectNameToStruct(t *testing.T) {
} }
func TestConvertType(t *testing.T) { func TestConvertType(t *testing.T) {
t.Parallel()
// Test Basic Struct // Test Basic Struct
type T struct { type T struct {
X *big.Int X *big.Int

View file

@ -24,6 +24,7 @@ import (
) )
func TestParseSelector(t *testing.T) { func TestParseSelector(t *testing.T) {
t.Parallel()
mkType := func(types ...interface{}) []ArgumentMarshaling { mkType := func(types ...interface{}) []ArgumentMarshaling {
var result []ArgumentMarshaling var result []ArgumentMarshaling
for i, typeOrComponents := range types { for i, typeOrComponents := range types {

View file

@ -26,6 +26,7 @@ import (
) )
func TestMakeTopics(t *testing.T) { func TestMakeTopics(t *testing.T) {
t.Parallel()
type args struct { type args struct {
query [][]interface{} query [][]interface{}
} }
@ -117,7 +118,9 @@ func TestMakeTopics(t *testing.T) {
}, },
} }
for _, tt := range tests { for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := MakeTopics(tt.args.query...) got, err := MakeTopics(tt.args.query...)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Errorf("makeTopics() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("makeTopics() error = %v, wantErr %v", err, tt.wantErr)
@ -347,10 +350,13 @@ func setupTopicsTests() []topicTest {
} }
func TestParseTopics(t *testing.T) { func TestParseTopics(t *testing.T) {
t.Parallel()
tests := setupTopicsTests() tests := setupTopicsTests()
for _, tt := range tests { for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel()
createObj := tt.args.createObj() createObj := tt.args.createObj()
if err := ParseTopics(createObj, tt.args.fields, tt.args.topics); (err != nil) != tt.wantErr { if err := ParseTopics(createObj, tt.args.fields, tt.args.topics); (err != nil) != tt.wantErr {
t.Errorf("parseTopics() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("parseTopics() error = %v, wantErr %v", err, tt.wantErr)
@ -364,10 +370,13 @@ func TestParseTopics(t *testing.T) {
} }
func TestParseTopicsIntoMap(t *testing.T) { func TestParseTopicsIntoMap(t *testing.T) {
t.Parallel()
tests := setupTopicsTests() tests := setupTopicsTests()
for _, tt := range tests { for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel()
outMap := make(map[string]interface{}) outMap := make(map[string]interface{})
if err := ParseTopicsIntoMap(outMap, tt.args.fields, tt.args.topics); (err != nil) != tt.wantErr { if err := ParseTopicsIntoMap(outMap, tt.args.fields, tt.args.topics); (err != nil) != tt.wantErr {
t.Errorf("parseTopicsIntoMap() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("parseTopicsIntoMap() error = %v, wantErr %v", err, tt.wantErr)

View file

@ -31,6 +31,7 @@ type typeWithoutStringer Type
// Tests that all allowed types get recognized by the type parser. // Tests that all allowed types get recognized by the type parser.
func TestTypeRegexp(t *testing.T) { func TestTypeRegexp(t *testing.T) {
t.Parallel()
tests := []struct { tests := []struct {
blob string blob string
components []ArgumentMarshaling components []ArgumentMarshaling
@ -117,6 +118,7 @@ func TestTypeRegexp(t *testing.T) {
} }
func TestTypeCheck(t *testing.T) { func TestTypeCheck(t *testing.T) {
t.Parallel()
for i, test := range []struct { for i, test := range []struct {
typ string typ string
components []ArgumentMarshaling components []ArgumentMarshaling
@ -308,6 +310,7 @@ func TestTypeCheck(t *testing.T) {
} }
func TestInternalType(t *testing.T) { func TestInternalType(t *testing.T) {
t.Parallel()
components := []ArgumentMarshaling{{Name: "a", Type: "int64"}} components := []ArgumentMarshaling{{Name: "a", Type: "int64"}}
internalType := "struct a.b[]" internalType := "struct a.b[]"
kind := Type{ kind := Type{
@ -332,6 +335,7 @@ func TestInternalType(t *testing.T) {
} }
func TestGetTypeSize(t *testing.T) { func TestGetTypeSize(t *testing.T) {
t.Parallel()
var testCases = []struct { var testCases = []struct {
typ string typ string
components []ArgumentMarshaling components []ArgumentMarshaling
@ -368,6 +372,7 @@ func TestGetTypeSize(t *testing.T) {
} }
func TestNewFixedBytesOver32(t *testing.T) { func TestNewFixedBytesOver32(t *testing.T) {
t.Parallel()
_, err := NewType("bytes4096", "", nil) _, err := NewType("bytes4096", "", nil)
if err == nil { if err == nil {
t.Errorf("fixed bytes with size over 32 is not spec'd") t.Errorf("fixed bytes with size over 32 is not spec'd")

View file

@ -33,6 +33,7 @@ import (
// TestUnpack tests the general pack/unpack tests in packing_test.go // TestUnpack tests the general pack/unpack tests in packing_test.go
func TestUnpack(t *testing.T) { func TestUnpack(t *testing.T) {
t.Parallel()
for i, test := range packUnpackTests { for i, test := range packUnpackTests {
t.Run(strconv.Itoa(i)+" "+test.def, func(t *testing.T) { t.Run(strconv.Itoa(i)+" "+test.def, func(t *testing.T) {
//Unpack //Unpack
@ -224,6 +225,7 @@ var unpackTests = []unpackTest{
// TestLocalUnpackTests runs test specially designed only for unpacking. // TestLocalUnpackTests runs test specially designed only for unpacking.
// All test cases that can be used to test packing and unpacking should move to packing_test.go // All test cases that can be used to test packing and unpacking should move to packing_test.go
func TestLocalUnpackTests(t *testing.T) { func TestLocalUnpackTests(t *testing.T) {
t.Parallel()
for i, test := range unpackTests { for i, test := range unpackTests {
t.Run(strconv.Itoa(i), func(t *testing.T) { t.Run(strconv.Itoa(i), func(t *testing.T) {
//Unpack //Unpack
@ -251,6 +253,7 @@ func TestLocalUnpackTests(t *testing.T) {
} }
func TestUnpackIntoInterfaceSetDynamicArrayOutput(t *testing.T) { func TestUnpackIntoInterfaceSetDynamicArrayOutput(t *testing.T) {
t.Parallel()
abi, err := JSON(strings.NewReader(`[{"constant":true,"inputs":[],"name":"testDynamicFixedBytes15","outputs":[{"name":"","type":"bytes15[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"testDynamicFixedBytes32","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"}]`)) abi, err := JSON(strings.NewReader(`[{"constant":true,"inputs":[],"name":"testDynamicFixedBytes15","outputs":[{"name":"","type":"bytes15[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"testDynamicFixedBytes32","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"}]`))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -321,6 +324,7 @@ func methodMultiReturn(require *require.Assertions) (ABI, []byte, methodMultiOut
} }
func TestMethodMultiReturn(t *testing.T) { func TestMethodMultiReturn(t *testing.T) {
t.Parallel()
type reversed struct { type reversed struct {
String string String string
Int *big.Int Int *big.Int
@ -400,6 +404,7 @@ func TestMethodMultiReturn(t *testing.T) {
} }
func TestMultiReturnWithArray(t *testing.T) { func TestMultiReturnWithArray(t *testing.T) {
t.Parallel()
const definition = `[{"name" : "multi", "type": "function", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]` const definition = `[{"name" : "multi", "type": "function", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]`
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
if err != nil { if err != nil {
@ -423,6 +428,7 @@ func TestMultiReturnWithArray(t *testing.T) {
} }
func TestMultiReturnWithStringArray(t *testing.T) { func TestMultiReturnWithStringArray(t *testing.T) {
t.Parallel()
const definition = `[{"name" : "multi", "type": "function", "outputs": [{"name": "","type": "uint256[3]"},{"name": "","type": "address"},{"name": "","type": "string[2]"},{"name": "","type": "bool"}]}]` const definition = `[{"name" : "multi", "type": "function", "outputs": [{"name": "","type": "uint256[3]"},{"name": "","type": "address"},{"name": "","type": "string[2]"},{"name": "","type": "bool"}]}]`
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
if err != nil { if err != nil {
@ -453,6 +459,7 @@ func TestMultiReturnWithStringArray(t *testing.T) {
} }
func TestMultiReturnWithStringSlice(t *testing.T) { func TestMultiReturnWithStringSlice(t *testing.T) {
t.Parallel()
const definition = `[{"name" : "multi", "type": "function", "outputs": [{"name": "","type": "string[]"},{"name": "","type": "uint256[]"}]}]` const definition = `[{"name" : "multi", "type": "function", "outputs": [{"name": "","type": "string[]"},{"name": "","type": "uint256[]"}]}]`
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
if err != nil { if err != nil {
@ -485,6 +492,7 @@ func TestMultiReturnWithStringSlice(t *testing.T) {
} }
func TestMultiReturnWithDeeplyNestedArray(t *testing.T) { func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
t.Parallel()
// Similar to TestMultiReturnWithArray, but with a special case in mind: // Similar to TestMultiReturnWithArray, but with a special case in mind:
// values of nested static arrays count towards the size as well, and any element following // values of nested static arrays count towards the size as well, and any element following
// after such nested array argument should be read with the correct offset, // after such nested array argument should be read with the correct offset,
@ -525,6 +533,7 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
} }
func TestUnmarshal(t *testing.T) { func TestUnmarshal(t *testing.T) {
t.Parallel()
const definition = `[ const definition = `[
{ "name" : "int", "type": "function", "outputs": [ { "type": "uint256" } ] }, { "name" : "int", "type": "function", "outputs": [ { "type": "uint256" } ] },
{ "name" : "bool", "type": "function", "outputs": [ { "type": "bool" } ] }, { "name" : "bool", "type": "function", "outputs": [ { "type": "bool" } ] },
@ -774,6 +783,7 @@ func TestUnmarshal(t *testing.T) {
} }
func TestUnpackTuple(t *testing.T) { func TestUnpackTuple(t *testing.T) {
t.Parallel()
const simpleTuple = `[{"name":"tuple","type":"function","outputs":[{"type":"tuple","name":"ret","components":[{"type":"int256","name":"a"},{"type":"int256","name":"b"}]}]}]` const simpleTuple = `[{"name":"tuple","type":"function","outputs":[{"type":"tuple","name":"ret","components":[{"type":"int256","name":"a"},{"type":"int256","name":"b"}]}]}]`
abi, err := JSON(strings.NewReader(simpleTuple)) abi, err := JSON(strings.NewReader(simpleTuple))
if err != nil { if err != nil {
@ -876,6 +886,7 @@ func TestUnpackTuple(t *testing.T) {
} }
func TestOOMMaliciousInput(t *testing.T) { func TestOOMMaliciousInput(t *testing.T) {
t.Parallel()
oomTests := []unpackTest{ oomTests := []unpackTest{
{ {
def: `[{"type": "uint8[]"}]`, def: `[{"type": "uint8[]"}]`,
@ -946,6 +957,7 @@ func TestOOMMaliciousInput(t *testing.T) {
} }
func TestPackAndUnpackIncompatibleNumber(t *testing.T) { func TestPackAndUnpackIncompatibleNumber(t *testing.T) {
t.Parallel()
var encodeABI Arguments var encodeABI Arguments
uint256Ty, err := NewType("uint256", "", nil) uint256Ty, err := NewType("uint256", "", nil)
if err != nil { if err != nil {

View file

@ -24,6 +24,7 @@ import (
) )
func TestTextHash(t *testing.T) { func TestTextHash(t *testing.T) {
t.Parallel()
hash := TextHash([]byte("Hello Joe")) hash := TextHash([]byte("Hello Joe"))
want := hexutil.MustDecode("0xa080337ae51c4e064c189e113edd0ba391df9206e2f49db658bb32cf2911730b") want := hexutil.MustDecode("0xa080337ae51c4e064c189e113edd0ba391df9206e2f49db658bb32cf2911730b")
if !bytes.Equal(hash, want) { if !bytes.Equal(hash, want) {

View file

@ -25,6 +25,7 @@ import (
// Tests that HD derivation paths can be correctly parsed into our internal binary // Tests that HD derivation paths can be correctly parsed into our internal binary
// representation. // representation.
func TestHDPathParsing(t *testing.T) { func TestHDPathParsing(t *testing.T) {
t.Parallel()
tests := []struct { tests := []struct {
input string input string
output DerivationPath output DerivationPath
@ -89,6 +90,7 @@ func testDerive(t *testing.T, next func() DerivationPath, expected []string) {
} }
func TestHdPathIteration(t *testing.T) { func TestHdPathIteration(t *testing.T) {
t.Parallel()
testDerive(t, DefaultIterator(DefaultBaseDerivationPath), testDerive(t, DefaultIterator(DefaultBaseDerivationPath),
[]string{ []string{
"m/44'/60'/0'/0/0", "m/44'/60'/0'/0/1", "m/44'/60'/0'/0/0", "m/44'/60'/0'/0/1",

View file

@ -152,6 +152,7 @@ func TestWatchNoDir(t *testing.T) {
} }
func TestCacheInitialReload(t *testing.T) { func TestCacheInitialReload(t *testing.T) {
t.Parallel()
cache, _ := newAccountCache(cachetestDir) cache, _ := newAccountCache(cachetestDir)
accounts := cache.accounts() accounts := cache.accounts()
if !reflect.DeepEqual(accounts, cachetestAccounts) { if !reflect.DeepEqual(accounts, cachetestAccounts) {
@ -160,6 +161,7 @@ func TestCacheInitialReload(t *testing.T) {
} }
func TestCacheAddDeleteOrder(t *testing.T) { func TestCacheAddDeleteOrder(t *testing.T) {
t.Parallel()
cache, _ := newAccountCache("testdata/no-such-dir") cache, _ := newAccountCache("testdata/no-such-dir")
cache.watcher.running = true // prevent unexpected reloads cache.watcher.running = true // prevent unexpected reloads
@ -244,6 +246,7 @@ func TestCacheAddDeleteOrder(t *testing.T) {
} }
func TestCacheFind(t *testing.T) { func TestCacheFind(t *testing.T) {
t.Parallel()
dir := filepath.Join("testdata", "dir") dir := filepath.Join("testdata", "dir")
cache, _ := newAccountCache(dir) cache, _ := newAccountCache(dir)
cache.watcher.running = true // prevent unexpected reloads cache.watcher.running = true // prevent unexpected reloads

View file

@ -36,6 +36,7 @@ import (
var testSigData = make([]byte, 32) var testSigData = make([]byte, 32)
func TestKeyStore(t *testing.T) { func TestKeyStore(t *testing.T) {
t.Parallel()
dir, ks := tmpKeyStore(t, true) dir, ks := tmpKeyStore(t, true)
a, err := ks.NewAccount("foo") a, err := ks.NewAccount("foo")
@ -70,6 +71,7 @@ func TestKeyStore(t *testing.T) {
} }
func TestSign(t *testing.T) { func TestSign(t *testing.T) {
t.Parallel()
_, ks := tmpKeyStore(t, true) _, ks := tmpKeyStore(t, true)
pass := "" // not used but required by API pass := "" // not used but required by API
@ -86,6 +88,7 @@ func TestSign(t *testing.T) {
} }
func TestSignWithPassphrase(t *testing.T) { func TestSignWithPassphrase(t *testing.T) {
t.Parallel()
_, ks := tmpKeyStore(t, true) _, ks := tmpKeyStore(t, true)
pass := "passwd" pass := "passwd"
@ -280,6 +283,7 @@ type walletEvent struct {
// Tests that wallet notifications and correctly fired when accounts are added // Tests that wallet notifications and correctly fired when accounts are added
// or deleted from the keystore. // or deleted from the keystore.
func TestWalletNotifications(t *testing.T) { func TestWalletNotifications(t *testing.T) {
t.Parallel()
_, ks := tmpKeyStore(t, false) _, ks := tmpKeyStore(t, false)
// Subscribe to the wallet feed and collect events. // Subscribe to the wallet feed and collect events.
@ -341,6 +345,7 @@ func TestWalletNotifications(t *testing.T) {
// TestImportExport tests the import functionality of a keystore. // TestImportExport tests the import functionality of a keystore.
func TestImportECDSA(t *testing.T) { func TestImportECDSA(t *testing.T) {
t.Parallel()
_, ks := tmpKeyStore(t, true) _, ks := tmpKeyStore(t, true)
key, err := crypto.GenerateKey() key, err := crypto.GenerateKey()
if err != nil { if err != nil {
@ -359,6 +364,7 @@ func TestImportECDSA(t *testing.T) {
// TestImportECDSA tests the import and export functionality of a keystore. // TestImportECDSA tests the import and export functionality of a keystore.
func TestImportExport(t *testing.T) { func TestImportExport(t *testing.T) {
t.Parallel()
_, ks := tmpKeyStore(t, true) _, ks := tmpKeyStore(t, true)
acc, err := ks.NewAccount("old") acc, err := ks.NewAccount("old")
if err != nil { if err != nil {
@ -387,6 +393,7 @@ func TestImportExport(t *testing.T) {
// TestImportRace tests the keystore on races. // TestImportRace tests the keystore on races.
// This test should fail under -race if importing races. // This test should fail under -race if importing races.
func TestImportRace(t *testing.T) { func TestImportRace(t *testing.T) {
t.Parallel()
_, ks := tmpKeyStore(t, true) _, ks := tmpKeyStore(t, true)
acc, err := ks.NewAccount("old") acc, err := ks.NewAccount("old")
if err != nil { if err != nil {

View file

@ -30,6 +30,7 @@ const (
// Tests that a json key file can be decrypted and encrypted in multiple rounds. // Tests that a json key file can be decrypted and encrypted in multiple rounds.
func TestKeyEncryptDecrypt(t *testing.T) { func TestKeyEncryptDecrypt(t *testing.T) {
t.Parallel()
keyjson, err := os.ReadFile("testdata/very-light-scrypt.json") keyjson, err := os.ReadFile("testdata/very-light-scrypt.json")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -40,6 +40,7 @@ func tmpKeyStoreIface(t *testing.T, encrypted bool) (dir string, ks keyStore) {
} }
func TestKeyStorePlain(t *testing.T) { func TestKeyStorePlain(t *testing.T) {
t.Parallel()
_, ks := tmpKeyStoreIface(t, false) _, ks := tmpKeyStoreIface(t, false)
pass := "" // not used but required by API pass := "" // not used but required by API
@ -60,6 +61,7 @@ func TestKeyStorePlain(t *testing.T) {
} }
func TestKeyStorePassphrase(t *testing.T) { func TestKeyStorePassphrase(t *testing.T) {
t.Parallel()
_, ks := tmpKeyStoreIface(t, true) _, ks := tmpKeyStoreIface(t, true)
pass := "foo" pass := "foo"
@ -80,6 +82,7 @@ func TestKeyStorePassphrase(t *testing.T) {
} }
func TestKeyStorePassphraseDecryptionFail(t *testing.T) { func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
t.Parallel()
_, ks := tmpKeyStoreIface(t, true) _, ks := tmpKeyStoreIface(t, true)
pass := "foo" pass := "foo"
@ -93,6 +96,7 @@ func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
} }
func TestImportPreSaleKey(t *testing.T) { func TestImportPreSaleKey(t *testing.T) {
t.Parallel()
dir, ks := tmpKeyStoreIface(t, true) dir, ks := tmpKeyStoreIface(t, true)
// file content of a presale key file generated with: // file content of a presale key file generated with:

View file

@ -21,6 +21,7 @@ import (
) )
func TestURLParsing(t *testing.T) { func TestURLParsing(t *testing.T) {
t.Parallel()
url, err := parseURL("https://ethereum.org") url, err := parseURL("https://ethereum.org")
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
@ -40,6 +41,7 @@ func TestURLParsing(t *testing.T) {
} }
func TestURLString(t *testing.T) { func TestURLString(t *testing.T) {
t.Parallel()
url := URL{Scheme: "https", Path: "ethereum.org"} url := URL{Scheme: "https", Path: "ethereum.org"}
if url.String() != "https://ethereum.org" { if url.String() != "https://ethereum.org" {
t.Errorf("expected: %v, got: %v", "https://ethereum.org", url.String()) t.Errorf("expected: %v, got: %v", "https://ethereum.org", url.String())
@ -52,6 +54,7 @@ func TestURLString(t *testing.T) {
} }
func TestURLMarshalJSON(t *testing.T) { func TestURLMarshalJSON(t *testing.T) {
t.Parallel()
url := URL{Scheme: "https", Path: "ethereum.org"} url := URL{Scheme: "https", Path: "ethereum.org"}
json, err := url.MarshalJSON() json, err := url.MarshalJSON()
if err != nil { if err != nil {
@ -63,6 +66,7 @@ func TestURLMarshalJSON(t *testing.T) {
} }
func TestURLUnmarshalJSON(t *testing.T) { func TestURLUnmarshalJSON(t *testing.T) {
t.Parallel()
url := &URL{} url := &URL{}
err := url.UnmarshalJSON([]byte("\"https://ethereum.org\"")) err := url.UnmarshalJSON([]byte("\"https://ethereum.org\""))
if err != nil { if err != nil {
@ -77,6 +81,7 @@ func TestURLUnmarshalJSON(t *testing.T) {
} }
func TestURLComparison(t *testing.T) { func TestURLComparison(t *testing.T) {
t.Parallel()
tests := []struct { tests := []struct {
urlA URL urlA URL
urlB URL urlB URL

View file

@ -232,7 +232,7 @@ func abigen(c *cli.Context) error {
} }
func main() { func main() {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
if err := app.Run(os.Args); err != nil { if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)

View file

@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/p2p/netutil"
"golang.org/x/exp/slog"
) )
func main() { func main() {
@ -52,10 +53,10 @@ func main() {
) )
flag.Parse() flag.Parse()
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
glogger.Verbosity(log.Lvl(*verbosity)) glogger.Verbosity(slog.Level(*verbosity))
glogger.Vmodule(*vmodule) glogger.Vmodule(*vmodule)
log.Root().SetHandler(glogger) log.SetDefault(log.NewLogger(glogger))
natm, err := nat.Parse(*natdesc) natm, err := nat.Parse(*natdesc)
if err != nil { if err != nil {

View file

@ -57,6 +57,7 @@ import (
"github.com/mattn/go-colorable" "github.com/mattn/go-colorable"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/exp/slog"
) )
const legalWarning = ` const legalWarning = `
@ -492,7 +493,7 @@ func initialize(c *cli.Context) error {
if usecolor { if usecolor {
output = colorable.NewColorable(logOutput) output = colorable.NewColorable(logOutput)
} }
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int(logLevelFlag.Name)), log.StreamHandler(output, log.TerminalFormat(usecolor)))) log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(output, slog.Level(c.Int(logLevelFlag.Name)), usecolor)))
return nil return nil
} }

View file

@ -54,7 +54,7 @@ func runTests(ctx *cli.Context, tests []utesting.Test) error {
} }
// Disable logging unless explicitly enabled. // Disable logging unless explicitly enabled.
if !ctx.IsSet("verbosity") && !ctx.IsSet("vmodule") { if !ctx.IsSet("verbosity") && !ctx.IsSet("vmodule") {
log.Root().SetHandler(log.DiscardHandler()) log.SetDefault(log.NewLogger(log.DiscardHandler()))
} }
// Run the tests. // Run the tests.
var run = utesting.RunTests var run = utesting.RunTests

View file

@ -88,7 +88,7 @@ type Env struct {
CurrentTimestamp uint64 `json:"currentTimestamp"` CurrentTimestamp uint64 `json:"currentTimestamp"`
Withdrawals []*Withdrawal `json:"withdrawals"` Withdrawals []*Withdrawal `json:"withdrawals"`
// optional // optional
CurrentDifficulty *big.Int `json:"currentDifficuly"` CurrentDifficulty *big.Int `json:"currentDifficulty"`
CurrentRandom *big.Int `json:"currentRandom"` CurrentRandom *big.Int `json:"currentRandom"`
CurrentBaseFee *big.Int `json:"currentBaseFee"` CurrentBaseFee *big.Int `json:"currentBaseFee"`
ParentDifficulty *big.Int `json:"parentDifficulty"` ParentDifficulty *big.Int `json:"parentDifficulty"`

View file

@ -24,6 +24,7 @@ import (
"regexp" "regexp"
"sort" "sort"
"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/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/eth/tracers/logger"
@ -85,7 +86,13 @@ func blockTestCmd(ctx *cli.Context) error {
continue continue
} }
test := tests[name] test := tests[name]
if err := test.Run(false, rawdb.HashScheme, tracer); err != nil { if err := test.Run(false, rawdb.HashScheme, tracer, func(res error, chain *core.BlockChain) {
if ctx.Bool(DumpFlag.Name) {
if state, _ := chain.State(); state != nil {
fmt.Println(string(state.Dump(nil)))
}
}
}); err != nil {
return fmt.Errorf("test %v: %w", name, err) return fmt.Errorf("test %v: %w", name, err)
} }
} }

View file

@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/exp/slog"
) )
//go:generate go run github.com/fjl/gencodec -type header -field-override headerMarshaling -out gen_header.go //go:generate go run github.com/fjl/gencodec -type header -field-override headerMarshaling -out gen_header.go
@ -216,9 +217,9 @@ func (i *bbInput) sealClique(block *types.Block) (*types.Block, error) {
// BuildBlock constructs a block from the given inputs. // BuildBlock constructs a block from the given inputs.
func BuildBlock(ctx *cli.Context) error { func BuildBlock(ctx *cli.Context) error {
// Configure the go-ethereum logger // Configure the go-ethereum logger
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) glogger.Verbosity(slog.Level(ctx.Int(VerbosityFlag.Name)))
log.Root().SetHandler(glogger) log.SetDefault(log.NewLogger(glogger))
baseDir, err := createBasedir(ctx) baseDir, err := createBasedir(ctx)
if err != nil { if err != nil {

View file

@ -234,7 +234,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
) )
evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
tracer.CaptureTxStart(evm, tx, msg.From) if tracer != nil {
tracer.CaptureTxStart(evm, tx, msg.From)
}
// (ret []byte, usedGas uint64, failed bool, err error) // (ret []byte, usedGas uint64, failed bool, err error)
msgResult, err := core.ApplyMessage(evm, msg, gaspool) msgResult, err := core.ApplyMessage(evm, msg, gaspool)
if err != nil { if err != nil {
@ -242,7 +244,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err) log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
gaspool.SetGas(prevGas) gaspool.SetGas(prevGas)
tracer.CaptureTxEnd(nil, err) if tracer != nil {
tracer.CaptureTxEnd(nil, err)
}
continue continue
} }
includedTxs = append(includedTxs, tx) includedTxs = append(includedTxs, tx)
@ -284,7 +288,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
//receipt.BlockNumber //receipt.BlockNumber
receipt.TransactionIndex = uint(txIndex) receipt.TransactionIndex = uint(txIndex)
receipts = append(receipts, receipt) receipts = append(receipts, receipt)
tracer.CaptureTxEnd(receipt, nil) if tracer != nil {
tracer.CaptureTxEnd(receipt, nil)
}
} }
txIndex++ txIndex++
@ -310,9 +316,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta)) reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta))
reward.Mul(reward, blockReward) reward.Mul(reward, blockReward)
reward.Div(reward, big.NewInt(8)) reward.Div(reward, big.NewInt(8))
statedb.AddBalance(ommer.Address, reward, state.BalanceChangeRewardMineUncle) statedb.AddBalance(ommer.Address, reward, state.BalanceIncreaseRewardMineUncle)
} }
statedb.AddBalance(pre.Env.Coinbase, minerReward, state.BalanceChangeRewardMineBlock) statedb.AddBalance(pre.Env.Coinbase, minerReward, state.BalanceIncreaseRewardMineBlock)
} }
// Apply withdrawals // Apply withdrawals
for _, w := range pre.Env.Withdrawals { for _, w := range pre.Env.Withdrawals {
@ -361,7 +367,7 @@ func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB
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)
statedb.SetBalance(addr, a.Balance, state.BalanceChangeGenesisBalance) statedb.SetBalance(addr, a.Balance, state.BalanceIncreaseGenesisBalance)
for k, v := range a.Storage { for k, v := range a.Storage {
statedb.SetState(addr, k, v) statedb.SetState(addr, k, v)
} }

View file

@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/tests" "github.com/ethereum/go-ethereum/tests"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/exp/slog"
) )
type result struct { type result struct {
@ -66,9 +67,9 @@ func (r *result) MarshalJSON() ([]byte, error) {
func Transaction(ctx *cli.Context) error { func Transaction(ctx *cli.Context) error {
// Configure the go-ethereum logger // Configure the go-ethereum logger
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) glogger.Verbosity(slog.Level(ctx.Int(VerbosityFlag.Name)))
log.Root().SetHandler(glogger) log.SetDefault(log.NewLogger(glogger))
var ( var (
err error err error

View file

@ -24,6 +24,8 @@ import (
"os" "os"
"path" "path"
"golang.org/x/exp/slog"
"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/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip1559"
@ -81,9 +83,9 @@ type input struct {
func Transition(ctx *cli.Context) error { func Transition(ctx *cli.Context) error {
// Configure the go-ethereum logger // Configure the go-ethereum logger
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) glogger.Verbosity(slog.Level(ctx.Int(VerbosityFlag.Name)))
log.Root().SetHandler(glogger) log.SetDefault(log.NewLogger(glogger))
var ( var (
err error err error

View file

@ -202,7 +202,7 @@ func initGenesis(ctx *cli.Context) error {
triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle()) triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle())
defer triedb.Close() defer triedb.Close()
_, hash, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides, nil) _, hash, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides)
if err != nil { if err != nil {
utils.Fatalf("Failed to write genesis block: %v", err) utils.Fatalf("Failed to write genesis block: %v", err)
} }
@ -474,11 +474,6 @@ func dump(ctx *cli.Context) error {
if ctx.Bool(utils.IterativeOutputFlag.Name) { if ctx.Bool(utils.IterativeOutputFlag.Name) {
state.IterativeDump(conf, json.NewEncoder(os.Stdout)) state.IterativeDump(conf, json.NewEncoder(os.Stdout))
} else { } else {
if conf.OnlyWithAddresses {
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.")
return errors.New("incompatible options")
}
fmt.Println(string(state.Dump(conf))) fmt.Println(string(state.Dump(conf)))
} }
return nil return nil

View file

@ -28,6 +28,7 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"testing" "testing"
"encoding/json"
"github.com/ethereum/go-ethereum/internal/reexec" "github.com/ethereum/go-ethereum/internal/reexec"
) )
@ -98,6 +99,53 @@ func testConsoleLogging(t *testing.T, format string, tStart, tEnd int) {
} }
} }
func TestJsonLogging(t *testing.T) {
t.Parallel()
haveB, err := runSelf("--log.format", "json", "logtest")
if err != nil {
t.Fatal(err)
}
readFile, err := os.Open("testdata/logging/logtest-json.txt")
if err != nil {
t.Fatal(err)
}
wantLines := split(readFile)
haveLines := split(bytes.NewBuffer(haveB))
for i, wantLine := range wantLines {
if i > len(haveLines)-1 {
t.Fatalf("format %v, line %d missing, want:%v", "json", i, wantLine)
}
haveLine := haveLines[i]
for strings.Contains(haveLine, "Unknown config environment variable") {
// This can happen on CI runs. Drop it.
haveLines = append(haveLines[:i], haveLines[i+1:]...)
haveLine = haveLines[i]
}
var have, want []byte
{
var h map[string]any
if err := json.Unmarshal([]byte(haveLine), &h); err != nil {
t.Fatal(err)
}
h["t"] = "xxx"
have, _ = json.Marshal(h)
}
{
var w map[string]any
if err := json.Unmarshal([]byte(wantLine), &w); err != nil {
t.Fatal(err)
}
w["t"] = "xxx"
want, _ = json.Marshal(w)
}
if !bytes.Equal(have, want) {
// show an intelligent diff
t.Logf(nicediff(have, want))
t.Errorf("file content wrong")
}
}
}
func TestVmodule(t *testing.T) { func TestVmodule(t *testing.T) {
t.Parallel() t.Parallel()
checkOutput := func(level int, want, wantNot string) { checkOutput := func(level int, want, wantNot string) {

View file

@ -26,6 +26,7 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/holiman/uint256" "github.com/holiman/uint256"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@ -42,6 +43,7 @@ This command is only meant for testing.
type customQuotedStringer struct { type customQuotedStringer struct {
} }
func (c customQuotedStringer) String() string { func (c customQuotedStringer) String() string {
return "output with 'quotes'" return "output with 'quotes'"
} }
@ -49,7 +51,9 @@ func (c customQuotedStringer) String() string {
// logTest is an entry point which spits out some logs. This is used by testing // logTest is an entry point which spits out some logs. This is used by testing
// to verify expected outputs // to verify expected outputs
func logTest(ctx *cli.Context) error { func logTest(ctx *cli.Context) error {
log.ResetGlobalState() // clear field padding map
debug.ResetLogging()
{ // big.Int { // big.Int
ba, _ := new(big.Int).SetString("111222333444555678999", 10) // "111,222,333,444,555,678,999" ba, _ := new(big.Int).SetString("111222333444555678999", 10) // "111,222,333,444,555,678,999"
bb, _ := new(big.Int).SetString("-111222333444555678999", 10) // "-111,222,333,444,555,678,999" bb, _ := new(big.Int).SetString("-111222333444555678999", 10) // "-111,222,333,444,555,678,999"
@ -77,8 +81,6 @@ func logTest(ctx *cli.Context) error {
log.Info("uint64", "18,446,744,073,709,551,615", uint64(math.MaxUint64)) log.Info("uint64", "18,446,744,073,709,551,615", uint64(math.MaxUint64))
} }
{ // Special characters { // Special characters
log.Info("Special chars in value", "key", "special \r\n\t chars") log.Info("Special chars in value", "key", "special \r\n\t chars")
log.Info("Special chars in key", "special \n\t chars", "value") log.Info("Special chars in key", "special \n\t chars", "value")
@ -100,9 +102,6 @@ func logTest(ctx *cli.Context) error {
var c customQuotedStringer var c customQuotedStringer
log.Info("a custom stringer that emits quoted text", "output", c) log.Info("a custom stringer that emits quoted text", "output", c)
} }
{ // Lazy eval
log.Info("Lazy evaluation of value", "key", log.Lazy{Fn: func() interface{} { return "lazy value" }})
}
{ // Multi-line message { // Multi-line message
log.Info("A message with wonky \U0001F4A9 characters") log.Info("A message with wonky \U0001F4A9 characters")
log.Info("A multiline message \nINFO [10-18|14:11:31.106] with wonky characters \U0001F4A9") log.Info("A multiline message \nINFO [10-18|14:11:31.106] with wonky characters \U0001F4A9")
@ -163,6 +162,10 @@ func logTest(ctx *cli.Context) error {
{ // Logging with 'reserved' keys { // Logging with 'reserved' keys
log.Info("Using keys 't', 'lvl', 'time', 'level' and 'msg'", "t", "t", "time", "time", "lvl", "lvl", "level", "level", "msg", "msg") log.Info("Using keys 't', 'lvl', 'time', 'level' and 'msg'", "t", "t", "time", "time", "lvl", "lvl", "level", "level", "msg", "msg")
} }
{ // Logging with wrong attr-value pairs
log.Info("Odd pair (1 attr)", "key")
log.Info("Odd pair (3 attr)", "key", "value", "key2")
}
return nil return nil
} }

View file

@ -146,6 +146,8 @@ var (
utils.GpoMaxGasPriceFlag, utils.GpoMaxGasPriceFlag,
utils.GpoIgnoreGasPriceFlag, utils.GpoIgnoreGasPriceFlag,
configFileFlag, configFileFlag,
utils.LogDebugFlag,
utils.LogBacktraceAtFlag,
}, utils.NetworkFlags, utils.DatabaseFlags) }, utils.NetworkFlags, utils.DatabaseFlags)
rpcFlags = []cli.Flag{ rpcFlags = []cli.Flag{

View file

@ -580,11 +580,11 @@ func dumpState(ctx *cli.Context) error {
return err return err
} }
da := &state.DumpAccount{ da := &state.DumpAccount{
Balance: account.Balance.String(), Balance: account.Balance.String(),
Nonce: account.Nonce, Nonce: account.Nonce,
Root: account.Root.Bytes(), Root: account.Root.Bytes(),
CodeHash: account.CodeHash, CodeHash: account.CodeHash,
SecureKey: accIt.Hash().Bytes(), AddressHash: accIt.Hash().Bytes(),
} }
if !conf.SkipCode && !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) { if !conf.SkipCode && !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) {
da.Code = rawdb.ReadCode(db, common.BytesToHash(account.CodeHash)) da.Code = rawdb.ReadCode(db, common.BytesToHash(account.CodeHash))

View file

@ -1,49 +1,52 @@
{"111,222,333,444,555,678,999":"111222333444555678999","lvl":"info","msg":"big.Int","t":"2023-11-09T08:33:19.464383209+01:00"} {"t":"2023-11-22T15:42:00.407963+08:00","lvl":"info","msg":"big.Int","111,222,333,444,555,678,999":"111222333444555678999"}
{"-111,222,333,444,555,678,999":"-111222333444555678999","lvl":"info","msg":"-big.Int","t":"2023-11-09T08:33:19.46455928+01:00"} {"t":"2023-11-22T15:42:00.408084+08:00","lvl":"info","msg":"-big.Int","-111,222,333,444,555,678,999":"-111222333444555678999"}
{"11,122,233,344,455,567,899,900":"11122233344455567899900","lvl":"info","msg":"big.Int","t":"2023-11-09T08:33:19.464582073+01:00"} {"t":"2023-11-22T15:42:00.408092+08:00","lvl":"info","msg":"big.Int","11,122,233,344,455,567,899,900":"11122233344455567899900"}
{"-11,122,233,344,455,567,899,900":"-11122233344455567899900","lvl":"info","msg":"-big.Int","t":"2023-11-09T08:33:19.464594846+01:00"} {"t":"2023-11-22T15:42:00.408097+08:00","lvl":"info","msg":"-big.Int","-11,122,233,344,455,567,899,900":"-11122233344455567899900"}
{"111,222,333,444,555,678,999":"0x607851afc94ca2517","lvl":"info","msg":"uint256","t":"2023-11-09T08:33:19.464607873+01:00"} {"t":"2023-11-22T15:42:00.408127+08:00","lvl":"info","msg":"uint256","111,222,333,444,555,678,999":"111222333444555678999"}
{"11,122,233,344,455,567,899,900":"0x25aeffe8aaa1ef67cfc","lvl":"info","msg":"uint256","t":"2023-11-09T08:33:19.464694639+01:00"} {"t":"2023-11-22T15:42:00.408133+08:00","lvl":"info","msg":"uint256","11,122,233,344,455,567,899,900":"11122233344455567899900"}
{"1,000,000":1000000,"lvl":"info","msg":"int64","t":"2023-11-09T08:33:19.464708835+01:00"} {"t":"2023-11-22T15:42:00.408137+08:00","lvl":"info","msg":"int64","1,000,000":1000000}
{"-1,000,000":-1000000,"lvl":"info","msg":"int64","t":"2023-11-09T08:33:19.464725054+01:00"} {"t":"2023-11-22T15:42:00.408145+08:00","lvl":"info","msg":"int64","-1,000,000":-1000000}
{"9,223,372,036,854,775,807":9223372036854775807,"lvl":"info","msg":"int64","t":"2023-11-09T08:33:19.464735773+01:00"} {"t":"2023-11-22T15:42:00.408149+08:00","lvl":"info","msg":"int64","9,223,372,036,854,775,807":9223372036854775807}
{"-9,223,372,036,854,775,808":-9223372036854775808,"lvl":"info","msg":"int64","t":"2023-11-09T08:33:19.464744532+01:00"} {"t":"2023-11-22T15:42:00.408153+08:00","lvl":"info","msg":"int64","-9,223,372,036,854,775,808":-9223372036854775808}
{"1,000,000":1000000,"lvl":"info","msg":"uint64","t":"2023-11-09T08:33:19.464752807+01:00"} {"t":"2023-11-22T15:42:00.408156+08:00","lvl":"info","msg":"uint64","1,000,000":1000000}
{"18,446,744,073,709,551,615":18446744073709551615,"lvl":"info","msg":"uint64","t":"2023-11-09T08:33:19.464779296+01:00"} {"t":"2023-11-22T15:42:00.40816+08:00","lvl":"info","msg":"uint64","18,446,744,073,709,551,615":18446744073709551615}
{"key":"special \r\n\t chars","lvl":"info","msg":"Special chars in value","t":"2023-11-09T08:33:19.464794181+01:00"} {"t":"2023-11-22T15:42:00.408164+08:00","lvl":"info","msg":"Special chars in value","key":"special \r\n\t chars"}
{"lvl":"info","msg":"Special chars in key","special \n\t chars":"value","t":"2023-11-09T08:33:19.464827197+01:00"} {"t":"2023-11-22T15:42:00.408167+08:00","lvl":"info","msg":"Special chars in key","special \n\t chars":"value"}
{"lvl":"info","msg":"nospace","nospace":"nospace","t":"2023-11-09T08:33:19.464841118+01:00"} {"t":"2023-11-22T15:42:00.408171+08:00","lvl":"info","msg":"nospace","nospace":"nospace"}
{"lvl":"info","msg":"with space","t":"2023-11-09T08:33:19.464862818+01:00","with nospace":"with nospace"} {"t":"2023-11-22T15:42:00.408174+08:00","lvl":"info","msg":"with space","with nospace":"with nospace"}
{"key":"\u001b[1G\u001b[K\u001b[1A","lvl":"info","msg":"Bash escapes in value","t":"2023-11-09T08:33:19.464876802+01:00"} {"t":"2023-11-22T15:42:00.408178+08:00","lvl":"info","msg":"Bash escapes in value","key":"\u001b[1G\u001b[K\u001b[1A"}
{"\u001b[1G\u001b[K\u001b[1A":"value","lvl":"info","msg":"Bash escapes in key","t":"2023-11-09T08:33:19.464885416+01:00"} {"t":"2023-11-22T15:42:00.408182+08:00","lvl":"info","msg":"Bash escapes in key","\u001b[1G\u001b[K\u001b[1A":"value"}
{"key":"value","lvl":"info","msg":"Bash escapes in message \u001b[1G\u001b[K\u001b[1A end","t":"2023-11-09T08:33:19.464906946+01:00"} {"t":"2023-11-22T15:42:00.408186+08:00","lvl":"info","msg":"Bash escapes in message \u001b[1G\u001b[K\u001b[1A end","key":"value"}
{"\u001b[35mColored\u001b[0m[":"\u001b[35mColored\u001b[0m[","lvl":"info","msg":"\u001b[35mColored\u001b[0m[","t":"2023-11-09T08:33:19.464921455+01:00"} {"t":"2023-11-22T15:42:00.408194+08:00","lvl":"info","msg":"\u001b[35mColored\u001b[0m[","\u001b[35mColored\u001b[0m[":"\u001b[35mColored\u001b[0m["}
{"2562047h47m16.854s":"2562047h47m16.854s","lvl":"info","msg":"Custom Stringer value","t":"2023-11-09T08:33:19.464943893+01:00"} {"t":"2023-11-22T15:42:00.408197+08:00","lvl":"info","msg":"an error message with quotes","error":"this is an 'error'"}
{"key":"lazy value","lvl":"info","msg":"Lazy evaluation of value","t":"2023-11-09T08:33:19.465013552+01:00"} {"t":"2023-11-22T15:42:00.408202+08:00","lvl":"info","msg":"Custom Stringer value","2562047h47m16.854s":"2562047h47m16.854s"}
{"lvl":"info","msg":"A message with wonky 💩 characters","t":"2023-11-09T08:33:19.465069437+01:00"} {"t":"2023-11-22T15:42:00.408208+08:00","lvl":"info","msg":"a custom stringer that emits quoted text","output":"output with 'quotes'"}
{"lvl":"info","msg":"A multiline message \nINFO [10-18|14:11:31.106] with wonky characters 💩","t":"2023-11-09T08:33:19.465083053+01:00"} {"t":"2023-11-22T15:42:00.408219+08:00","lvl":"info","msg":"A message with wonky 💩 characters"}
{"lvl":"info","msg":"A multiline message \nLALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above","t":"2023-11-09T08:33:19.465104289+01:00"} {"t":"2023-11-22T15:42:00.408222+08:00","lvl":"info","msg":"A multiline message \nINFO [10-18|14:11:31.106] with wonky characters 💩"}
{"false":"false","lvl":"info","msg":"boolean","t":"2023-11-09T08:33:19.465117185+01:00","true":"true"} {"t":"2023-11-22T15:42:00.408226+08:00","lvl":"info","msg":"A multiline message \nLALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above"}
{"foo":"beta","lvl":"info","msg":"repeated-key 1","t":"2023-11-09T08:33:19.465143425+01:00"} {"t":"2023-11-22T15:42:00.408229+08:00","lvl":"info","msg":"boolean","true":true,"false":false}
{"lvl":"info","msg":"repeated-key 2","t":"2023-11-09T08:33:19.465156323+01:00","xx":"longer"} {"t":"2023-11-22T15:42:00.408234+08:00","lvl":"info","msg":"repeated-key 1","foo":"alpha","foo":"beta"}
{"lvl":"info","msg":"log at level info","t":"2023-11-09T08:33:19.465193158+01:00"} {"t":"2023-11-22T15:42:00.408237+08:00","lvl":"info","msg":"repeated-key 2","xx":"short","xx":"longer"}
{"lvl":"warn","msg":"log at level warn","t":"2023-11-09T08:33:19.465228964+01:00"} {"t":"2023-11-22T15:42:00.408241+08:00","lvl":"info","msg":"log at level info"}
{"lvl":"eror","msg":"log at level error","t":"2023-11-09T08:33:19.465240352+01:00"} {"t":"2023-11-22T15:42:00.408244+08:00","lvl":"warn","msg":"log at level warn"}
{"a":"aligned left","bar":"short","lvl":"info","msg":"test","t":"2023-11-09T08:33:19.465247226+01:00"} {"t":"2023-11-22T15:42:00.408247+08:00","lvl":"eror","msg":"log at level error"}
{"a":1,"bar":"a long message","lvl":"info","msg":"test","t":"2023-11-09T08:33:19.465269028+01:00"} {"t":"2023-11-22T15:42:00.408251+08:00","lvl":"info","msg":"test","bar":"short","a":"aligned left"}
{"a":"aligned right","bar":"short","lvl":"info","msg":"test","t":"2023-11-09T08:33:19.465313611+01:00"} {"t":"2023-11-22T15:42:00.408254+08:00","lvl":"info","msg":"test","bar":"a long message","a":1}
{"lvl":"info","msg":"The following logs should align so that the key-fields make 5 columns","t":"2023-11-09T08:33:19.465328188+01:00"} {"t":"2023-11-22T15:42:00.408258+08:00","lvl":"info","msg":"test","bar":"short","a":"aligned right"}
{"gas":1123123,"hash":"0x0000000000000000000000000000000000000000000000000000000000001234","lvl":"info","msg":"Inserted known block","number":1012,"other":"first","t":"2023-11-09T08:33:19.465350507+01:00","txs":200} {"t":"2023-11-22T15:42:00.408261+08:00","lvl":"info","msg":"The following logs should align so that the key-fields make 5 columns"}
{"gas":1123,"hash":"0x0000000000000000000000000000000000000000000000000000000000001235","lvl":"info","msg":"Inserted new block","number":1,"other":"second","t":"2023-11-09T08:33:19.465387952+01:00","txs":2} {"t":"2023-11-22T15:42:00.408275+08:00","lvl":"info","msg":"Inserted known block","number":1012,"hash":"0x0000000000000000000000000000000000000000000000000000000000001234","txs":200,"gas":1123123,"other":"first"}
{"gas":1,"hash":"0x0000000000000000000000000000000000000000000000000000000000012322","lvl":"info","msg":"Inserted known block","number":99,"other":"third","t":"2023-11-09T08:33:19.465406687+01:00","txs":10} {"t":"2023-11-22T15:42:00.408281+08:00","lvl":"info","msg":"Inserted new block","number":1,"hash":"0x0000000000000000000000000000000000000000000000000000000000001235","txs":2,"gas":1123,"other":"second"}
{"gas":99,"hash":"0x0000000000000000000000000000000000000000000000000000000000001234","lvl":"warn","msg":"Inserted known block","number":1012,"other":"fourth","t":"2023-11-09T08:33:19.465433025+01:00","txs":200} {"t":"2023-11-22T15:42:00.408287+08:00","lvl":"info","msg":"Inserted known block","number":99,"hash":"0x0000000000000000000000000000000000000000000000000000000000012322","txs":10,"gas":1,"other":"third"}
{"\u003cnil\u003e":"\u003cnil\u003e","lvl":"info","msg":"(*big.Int)(nil)","t":"2023-11-09T08:33:19.465450283+01:00"} {"t":"2023-11-22T15:42:00.408296+08:00","lvl":"warn","msg":"Inserted known block","number":1012,"hash":"0x0000000000000000000000000000000000000000000000000000000000001234","txs":200,"gas":99,"other":"fourth"}
{"\u003cnil\u003e":"nil","lvl":"info","msg":"(*uint256.Int)(nil)","t":"2023-11-09T08:33:19.465472953+01:00"} {"t":"2023-11-22T15:42:00.4083+08:00","lvl":"info","msg":"(*big.Int)(nil)","<nil>":"<nil>"}
{"lvl":"info","msg":"(fmt.Stringer)(nil)","res":"\u003cnil\u003e","t":"2023-11-09T08:33:19.465538633+01:00"} {"t":"2023-11-22T15:42:00.408303+08:00","lvl":"info","msg":"(*uint256.Int)(nil)","<nil>":"<nil>"}
{"lvl":"info","msg":"nil-concrete-stringer","res":"nil","t":"2023-11-09T08:33:19.465552355+01:00"} {"t":"2023-11-22T15:42:00.408311+08:00","lvl":"info","msg":"(fmt.Stringer)(nil)","res":null}
{"lvl":"info","msg":"error(nil) ","res":"\u003cnil\u003e","t":"2023-11-09T08:33:19.465601029+01:00"} {"t":"2023-11-22T15:42:00.408318+08:00","lvl":"info","msg":"nil-concrete-stringer","res":"<nil>"}
{"lvl":"info","msg":"nil-concrete-error","res":"","t":"2023-11-09T08:33:19.46561622+01:00"} {"t":"2023-11-22T15:42:00.408322+08:00","lvl":"info","msg":"error(nil) ","res":null}
{"lvl":"info","msg":"nil-custom-struct","res":"\u003cnil\u003e","t":"2023-11-09T08:33:19.465638888+01:00"} {"t":"2023-11-22T15:42:00.408326+08:00","lvl":"info","msg":"nil-concrete-error","res":""}
{"lvl":"info","msg":"raw nil","res":"\u003cnil\u003e","t":"2023-11-09T08:33:19.465673664+01:00"} {"t":"2023-11-22T15:42:00.408334+08:00","lvl":"info","msg":"nil-custom-struct","res":null}
{"lvl":"info","msg":"(*uint64)(nil)","res":"\u003cnil\u003e","t":"2023-11-09T08:33:19.465700264+01:00"} {"t":"2023-11-22T15:42:00.40835+08:00","lvl":"info","msg":"raw nil","res":null}
{"level":"level","lvl":"lvl","msg":"msg","t":"t","time":"time"} {"t":"2023-11-22T15:42:00.408354+08:00","lvl":"info","msg":"(*uint64)(nil)","res":null}
{"t":"2023-11-22T15:42:00.408361+08:00","lvl":"info","msg":"Using keys 't', 'lvl', 'time', 'level' and 'msg'","t":"t","time":"time","lvl":"lvl","level":"level","msg":"msg"}
{"t":"2023-11-29T15:13:00.195655931+01:00","lvl":"info","msg":"Odd pair (1 attr)","key":null,"LOG_ERROR":"Normalized odd number of arguments by adding nil"}
{"t":"2023-11-29T15:13:00.195681832+01:00","lvl":"info","msg":"Odd pair (3 attr)","key":"value","key2":null,"LOG_ERROR":"Normalized odd number of arguments by adding nil"}

View file

@ -1,51 +1,52 @@
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=big.Int 111,222,333,444,555,678,999=111,222,333,444,555,678,999 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=big.Int 111,222,333,444,555,678,999=111222333444555678999
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=-big.Int -111,222,333,444,555,678,999=-111,222,333,444,555,678,999 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=-big.Int -111,222,333,444,555,678,999=-111222333444555678999
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=big.Int 11,122,233,344,455,567,899,900=11,122,233,344,455,567,899,900 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=big.Int 11,122,233,344,455,567,899,900=11122233344455567899900
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=-big.Int -11,122,233,344,455,567,899,900=-11,122,233,344,455,567,899,900 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=-big.Int -11,122,233,344,455,567,899,900=-11122233344455567899900
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=uint256 111,222,333,444,555,678,999=111,222,333,444,555,678,999 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=uint256 111,222,333,444,555,678,999=111222333444555678999
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=uint256 11,122,233,344,455,567,899,900=11,122,233,344,455,567,899,900 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=uint256 11,122,233,344,455,567,899,900=11122233344455567899900
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=int64 1,000,000=1,000,000 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=int64 1,000,000=1000000
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=int64 -1,000,000=-1,000,000 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=int64 -1,000,000=-1000000
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=int64 9,223,372,036,854,775,807=9,223,372,036,854,775,807 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=int64 9,223,372,036,854,775,807=9223372036854775807
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=int64 -9,223,372,036,854,775,808=-9,223,372,036,854,775,808 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=int64 -9,223,372,036,854,775,808=-9223372036854775808
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=uint64 1,000,000=1,000,000 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=uint64 1,000,000=1000000
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=uint64 18,446,744,073,709,551,615=18,446,744,073,709,551,615 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=uint64 18,446,744,073,709,551,615=18446744073709551615
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="Special chars in value" key="special \r\n\t chars" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Special chars in value" key="special \r\n\t chars"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="Special chars in key" "special \n\t chars"=value t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Special chars in key" "special \n\t chars"=value
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=nospace nospace=nospace t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=nospace nospace=nospace
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="with space" "with nospace"="with nospace" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="with space" "with nospace"="with nospace"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="Bash escapes in value" key="\x1b[1G\x1b[K\x1b[1A" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Bash escapes in value" key="\x1b[1G\x1b[K\x1b[1A"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="Bash escapes in key" "\x1b[1G\x1b[K\x1b[1A"=value t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Bash escapes in key" "\x1b[1G\x1b[K\x1b[1A"=value
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="Bash escapes in message \x1b[1G\x1b[K\x1b[1A end" key=value t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Bash escapes in message \x1b[1G\x1b[K\x1b[1A end" key=value
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="\x1b[35mColored\x1b[0m[" "\x1b[35mColored\x1b[0m["="\x1b[35mColored\x1b[0m[" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="\x1b[35mColored\x1b[0m[" "\x1b[35mColored\x1b[0m["="\x1b[35mColored\x1b[0m["
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="an error message with quotes" error="this is an 'error'" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="an error message with quotes" error="this is an 'error'"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="Custom Stringer value" 2562047h47m16.854s=2562047h47m16.854s t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Custom Stringer value" 2562047h47m16.854s=2562047h47m16.854s
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="a custom stringer that emits quoted text" output="output with 'quotes'" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="a custom stringer that emits quoted text" output="output with 'quotes'"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="Lazy evaluation of value" key="lazy value" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="A message with wonky 💩 characters"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="A message with wonky 💩 characters" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="A multiline message \nINFO [10-18|14:11:31.106] with wonky characters 💩"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="A multiline message \nINFO [10-18|14:11:31.106] with wonky characters 💩" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="A multiline message \nLALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="A multiline message \nLALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=boolean true=true false=false
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=boolean true=true false=false t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="repeated-key 1" foo=alpha foo=beta
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="repeated-key 1" foo=alpha foo=beta t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="repeated-key 2" xx=short xx=longer
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="repeated-key 2" xx=short xx=longer t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="log at level info"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="log at level info" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=warn msg="log at level warn"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=warn msg="log at level warn" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=eror msg="log at level error"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=eror msg="log at level error" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=test bar=short a="aligned left"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=test bar=short a="aligned left" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=test bar="a long message" a=1
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=test bar="a long message" a=1 t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=test bar=short a="aligned right"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=test bar=short a="aligned right" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="The following logs should align so that the key-fields make 5 columns"
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="The following logs should align so that the key-fields make 5 columns" t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Inserted known block" number=1012 hash=0x0000000000000000000000000000000000000000000000000000000000001234 txs=200 gas=1123123 other=first
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="Inserted known block" number=1012 hash=0x0000000000000000000000000000000000000000000000000000000000001234 txs=200 gas=1,123,123 other=first t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Inserted new block" number=1 hash=0x0000000000000000000000000000000000000000000000000000000000001235 txs=2 gas=1123 other=second
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="Inserted new block" number=1 hash=0x0000000000000000000000000000000000000000000000000000000000001235 txs=2 gas=1123 other=second t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Inserted known block" number=99 hash=0x0000000000000000000000000000000000000000000000000000000000012322 txs=10 gas=1 other=third
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="Inserted known block" number=99 hash=0x0000000000000000000000000000000000000000000000000000000000012322 txs=10 gas=1 other=third t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=warn msg="Inserted known block" number=1012 hash=0x0000000000000000000000000000000000000000000000000000000000001234 txs=200 gas=99 other=fourth
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=warn msg="Inserted known block" number=1012 hash=0x0000000000000000000000000000000000000000000000000000000000001234 txs=200 gas=99 other=fourth t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=(*big.Int)(nil) <nil>=<nil>
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=(*big.Int)(nil) <nil>=<nil> t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=(*uint256.Int)(nil) <nil>=<nil>
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=(*uint256.Int)(nil) <nil>=<nil> t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=(fmt.Stringer)(nil) res=<nil>
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=(fmt.Stringer)(nil) res=nil t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=nil-concrete-stringer res=<nil>
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=nil-concrete-stringer res=nil t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="error(nil) " res=<nil>
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="error(nil) " res=nil t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=nil-concrete-error res=""
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=nil-concrete-error res= t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=nil-custom-struct res=<nil>
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=nil-custom-struct res=<nil> t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="raw nil" res=<nil>
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="raw nil" res=nil t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg=(*uint64)(nil) res=<nil>
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg=(*uint64)(nil) res=<nil> t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Using keys 't', 'lvl', 'time', 'level' and 'msg'" t=t time=time lvl=lvl level=level msg=msg
t=xxxxxxxxxxxxxxxxxxxxxxxx lvl=info msg="Using keys 't', 'lvl', 'time', 'level' and 'msg'" t=t time=time lvl=lvl level=level msg=msg t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Odd pair (1 attr)" key=<nil> LOG_ERROR="Normalized odd number of arguments by adding nil"
t=xxxx-xx-xxTxx:xx:xx+xxxx lvl=info msg="Odd pair (3 attr)" key=value key2=<nil> LOG_ERROR="Normalized odd number of arguments by adding nil"

View file

@ -1,52 +1,53 @@
INFO [XX-XX|XX:XX:XX.XXX] big.Int 111,222,333,444,555,678,999=111,222,333,444,555,678,999 INFO [xx-xx|xx:xx:xx.xxx] big.Int 111,222,333,444,555,678,999=111,222,333,444,555,678,999
INFO [XX-XX|XX:XX:XX.XXX] -big.Int -111,222,333,444,555,678,999=-111,222,333,444,555,678,999 INFO [xx-xx|xx:xx:xx.xxx] -big.Int -111,222,333,444,555,678,999=-111,222,333,444,555,678,999
INFO [XX-XX|XX:XX:XX.XXX] big.Int 11,122,233,344,455,567,899,900=11,122,233,344,455,567,899,900 INFO [xx-xx|xx:xx:xx.xxx] big.Int 11,122,233,344,455,567,899,900=11,122,233,344,455,567,899,900
INFO [XX-XX|XX:XX:XX.XXX] -big.Int -11,122,233,344,455,567,899,900=-11,122,233,344,455,567,899,900 INFO [xx-xx|xx:xx:xx.xxx] -big.Int -11,122,233,344,455,567,899,900=-11,122,233,344,455,567,899,900
INFO [XX-XX|XX:XX:XX.XXX] uint256 111,222,333,444,555,678,999=111,222,333,444,555,678,999 INFO [xx-xx|xx:xx:xx.xxx] uint256 111,222,333,444,555,678,999=111,222,333,444,555,678,999
INFO [XX-XX|XX:XX:XX.XXX] uint256 11,122,233,344,455,567,899,900=11,122,233,344,455,567,899,900 INFO [xx-xx|xx:xx:xx.xxx] uint256 11,122,233,344,455,567,899,900=11,122,233,344,455,567,899,900
INFO [XX-XX|XX:XX:XX.XXX] int64 1,000,000=1,000,000 INFO [xx-xx|xx:xx:xx.xxx] int64 1,000,000=1,000,000
INFO [XX-XX|XX:XX:XX.XXX] int64 -1,000,000=-1,000,000 INFO [xx-xx|xx:xx:xx.xxx] int64 -1,000,000=-1,000,000
INFO [XX-XX|XX:XX:XX.XXX] int64 9,223,372,036,854,775,807=9,223,372,036,854,775,807 INFO [xx-xx|xx:xx:xx.xxx] int64 9,223,372,036,854,775,807=9,223,372,036,854,775,807
INFO [XX-XX|XX:XX:XX.XXX] int64 -9,223,372,036,854,775,808=-9,223,372,036,854,775,808 INFO [xx-xx|xx:xx:xx.xxx] int64 -9,223,372,036,854,775,808=-9,223,372,036,854,775,808
INFO [XX-XX|XX:XX:XX.XXX] uint64 1,000,000=1,000,000 INFO [xx-xx|xx:xx:xx.xxx] uint64 1,000,000=1,000,000
INFO [XX-XX|XX:XX:XX.XXX] uint64 18,446,744,073,709,551,615=18,446,744,073,709,551,615 INFO [xx-xx|xx:xx:xx.xxx] uint64 18,446,744,073,709,551,615=18,446,744,073,709,551,615
INFO [XX-XX|XX:XX:XX.XXX] Special chars in value key="special \r\n\t chars" INFO [xx-xx|xx:xx:xx.xxx] Special chars in value key="special \r\n\t chars"
INFO [XX-XX|XX:XX:XX.XXX] Special chars in key "special \n\t chars"=value INFO [xx-xx|xx:xx:xx.xxx] Special chars in key "special \n\t chars"=value
INFO [XX-XX|XX:XX:XX.XXX] nospace nospace=nospace INFO [xx-xx|xx:xx:xx.xxx] nospace nospace=nospace
INFO [XX-XX|XX:XX:XX.XXX] with space "with nospace"="with nospace" INFO [xx-xx|xx:xx:xx.xxx] with space "with nospace"="with nospace"
INFO [XX-XX|XX:XX:XX.XXX] Bash escapes in value key="\x1b[1G\x1b[K\x1b[1A" INFO [xx-xx|xx:xx:xx.xxx] Bash escapes in value key="\x1b[1G\x1b[K\x1b[1A"
INFO [XX-XX|XX:XX:XX.XXX] Bash escapes in key "\x1b[1G\x1b[K\x1b[1A"=value INFO [xx-xx|xx:xx:xx.xxx] Bash escapes in key "\x1b[1G\x1b[K\x1b[1A"=value
INFO [XX-XX|XX:XX:XX.XXX] "Bash escapes in message \x1b[1G\x1b[K\x1b[1A end" key=value INFO [xx-xx|xx:xx:xx.xxx] "Bash escapes in message \x1b[1G\x1b[K\x1b[1A end" key=value
INFO [XX-XX|XX:XX:XX.XXX] "\x1b[35mColored\x1b[0m[" "\x1b[35mColored\x1b[0m["="\x1b[35mColored\x1b[0m[" INFO [xx-xx|xx:xx:xx.xxx] "\x1b[35mColored\x1b[0m[" "\x1b[35mColored\x1b[0m["="\x1b[35mColored\x1b[0m["
INFO [XX-XX|XX:XX:XX.XXX] an error message with quotes error="this is an 'error'" INFO [xx-xx|xx:xx:xx.xxx] an error message with quotes error="this is an 'error'"
INFO [XX-XX|XX:XX:XX.XXX] Custom Stringer value 2562047h47m16.854s=2562047h47m16.854s INFO [xx-xx|xx:xx:xx.xxx] Custom Stringer value 2562047h47m16.854s=2562047h47m16.854s
INFO [XX-XX|XX:XX:XX.XXX] a custom stringer that emits quoted text output="output with 'quotes'" INFO [xx-xx|xx:xx:xx.xxx] a custom stringer that emits quoted text output="output with 'quotes'"
INFO [XX-XX|XX:XX:XX.XXX] Lazy evaluation of value key="lazy value" INFO [xx-xx|xx:xx:xx.xxx] "A message with wonky 💩 characters"
INFO [XX-XX|XX:XX:XX.XXX] "A message with wonky 💩 characters" INFO [xx-xx|xx:xx:xx.xxx] "A multiline message \nINFO [10-18|14:11:31.106] with wonky characters 💩"
INFO [XX-XX|XX:XX:XX.XXX] "A multiline message \nINFO [10-18|14:11:31.106] with wonky characters 💩" INFO [xx-xx|xx:xx:xx.xxx] A multiline message
INFO [XX-XX|XX:XX:XX.XXX] A multiline message
LALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above LALA [ZZZZZZZZZZZZZZZZZZ] Actually part of message above
INFO [XX-XX|XX:XX:XX.XXX] boolean true=true false=false INFO [xx-xx|xx:xx:xx.xxx] boolean true=true false=false
INFO [XX-XX|XX:XX:XX.XXX] repeated-key 1 foo=alpha foo=beta INFO [xx-xx|xx:xx:xx.xxx] repeated-key 1 foo=alpha foo=beta
INFO [XX-XX|XX:XX:XX.XXX] repeated-key 2 xx=short xx=longer INFO [xx-xx|xx:xx:xx.xxx] repeated-key 2 xx=short xx=longer
INFO [XX-XX|XX:XX:XX.XXX] log at level info INFO [xx-xx|xx:xx:xx.xxx] log at level info
WARN [XX-XX|XX:XX:XX.XXX] log at level warn WARN [xx-xx|xx:xx:xx.xxx] log at level warn
ERROR[XX-XX|XX:XX:XX.XXX] log at level error ERROR[xx-xx|xx:xx:xx.xxx] log at level error
INFO [XX-XX|XX:XX:XX.XXX] test bar=short a="aligned left" INFO [xx-xx|xx:xx:xx.xxx] test bar=short a="aligned left"
INFO [XX-XX|XX:XX:XX.XXX] test bar="a long message" a=1 INFO [xx-xx|xx:xx:xx.xxx] test bar="a long message" a=1
INFO [XX-XX|XX:XX:XX.XXX] test bar=short a="aligned right" INFO [xx-xx|xx:xx:xx.xxx] test bar=short a="aligned right"
INFO [XX-XX|XX:XX:XX.XXX] The following logs should align so that the key-fields make 5 columns INFO [xx-xx|xx:xx:xx.xxx] The following logs should align so that the key-fields make 5 columns
INFO [XX-XX|XX:XX:XX.XXX] Inserted known block number=1012 hash=000000..001234 txs=200 gas=1,123,123 other=first INFO [xx-xx|xx:xx:xx.xxx] Inserted known block number=1012 hash=000000..001234 txs=200 gas=1,123,123 other=first
INFO [XX-XX|XX:XX:XX.XXX] Inserted new block number=1 hash=000000..001235 txs=2 gas=1123 other=second INFO [xx-xx|xx:xx:xx.xxx] Inserted new block number=1 hash=000000..001235 txs=2 gas=1123 other=second
INFO [XX-XX|XX:XX:XX.XXX] Inserted known block number=99 hash=000000..012322 txs=10 gas=1 other=third INFO [xx-xx|xx:xx:xx.xxx] Inserted known block number=99 hash=000000..012322 txs=10 gas=1 other=third
WARN [XX-XX|XX:XX:XX.XXX] Inserted known block number=1012 hash=000000..001234 txs=200 gas=99 other=fourth WARN [xx-xx|xx:xx:xx.xxx] Inserted known block number=1012 hash=000000..001234 txs=200 gas=99 other=fourth
INFO [XX-XX|XX:XX:XX.XXX] (*big.Int)(nil) <nil>=<nil> INFO [xx-xx|xx:xx:xx.xxx] (*big.Int)(nil) <nil>=<nil>
INFO [XX-XX|XX:XX:XX.XXX] (*uint256.Int)(nil) <nil>=<nil> INFO [xx-xx|xx:xx:xx.xxx] (*uint256.Int)(nil) <nil>=<nil>
INFO [XX-XX|XX:XX:XX.XXX] (fmt.Stringer)(nil) res=nil INFO [xx-xx|xx:xx:xx.xxx] (fmt.Stringer)(nil) res=<nil>
INFO [XX-XX|XX:XX:XX.XXX] nil-concrete-stringer res=nil INFO [xx-xx|xx:xx:xx.xxx] nil-concrete-stringer res=<nil>
INFO [XX-XX|XX:XX:XX.XXX] error(nil) res=nil INFO [xx-xx|xx:xx:xx.xxx] error(nil) res=<nil>
INFO [XX-XX|XX:XX:XX.XXX] nil-concrete-error res= INFO [xx-xx|xx:xx:xx.xxx] nil-concrete-error res=
INFO [XX-XX|XX:XX:XX.XXX] nil-custom-struct res=<nil> INFO [xx-xx|xx:xx:xx.xxx] nil-custom-struct res=<nil>
INFO [XX-XX|XX:XX:XX.XXX] raw nil res=nil INFO [xx-xx|xx:xx:xx.xxx] raw nil res=<nil>
INFO [XX-XX|XX:XX:XX.XXX] (*uint64)(nil) res=<nil> INFO [xx-xx|xx:xx:xx.xxx] (*uint64)(nil) res=<nil>
INFO [XX-XX|XX:XX:XX.XXX] Using keys 't', 'lvl', 'time', 'level' and 'msg' t=t time=time lvl=lvl level=level msg=msg INFO [xx-xx|xx:xx:xx.xxx] Using keys 't', 'lvl', 'time', 'level' and 'msg' t=t time=time lvl=lvl level=level msg=msg
INFO [xx-xx|xx:xx:xx.xxx] Odd pair (1 attr) key=<nil> LOG_ERROR="Normalized odd number of arguments by adding nil"
INFO [xx-xx|xx:xx:xx.xxx] Odd pair (3 attr) key=value key2=<nil> LOG_ERROR="Normalized odd number of arguments by adding nil"

View file

@ -1395,6 +1395,13 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
log.Info(fmt.Sprintf("Using %s as db engine", dbEngine)) log.Info(fmt.Sprintf("Using %s as db engine", dbEngine))
cfg.DBEngine = dbEngine cfg.DBEngine = dbEngine
} }
// deprecation notice for log debug flags (TODO: find a more appropriate place to put these?)
if ctx.IsSet(LogBacktraceAtFlag.Name) {
log.Warn("log.backtrace flag is deprecated")
}
if ctx.IsSet(LogDebugFlag.Name) {
log.Warn("log.debug flag is deprecated")
}
} }
func setSmartCard(ctx *cli.Context, cfg *node.Config) { func setSmartCard(ctx *cli.Context, cfg *node.Config) {

View file

@ -45,6 +45,8 @@ var DeprecatedFlags = []cli.Flag{
LightMaxPeersFlag, LightMaxPeersFlag,
LightNoPruneFlag, LightNoPruneFlag,
LightNoSyncServeFlag, LightNoSyncServeFlag,
LogBacktraceAtFlag,
LogDebugFlag,
} }
var ( var (
@ -118,6 +120,18 @@ var (
Usage: "Enables serving light clients before syncing (deprecated)", Usage: "Enables serving light clients before syncing (deprecated)",
Category: flags.LightCategory, Category: flags.LightCategory,
} }
// Deprecated November 2023
LogBacktraceAtFlag = &cli.StringFlag{
Name: "log.backtrace",
Usage: "Request a stack trace at a specific logging statement (deprecated)",
Value: "",
Category: flags.DeprecatedCategory,
}
LogDebugFlag = &cli.BoolFlag{
Name: "log.debug",
Usage: "Prepends log messages with call-site location (deprecated)",
Category: flags.DeprecatedCategory,
}
) )
// showDeprecated displays deprecated flags that will be soon removed from the codebase. // showDeprecated displays deprecated flags that will be soon removed from the codebase.

View file

@ -23,6 +23,8 @@ import (
"math/big" "math/big"
"reflect" "reflect"
"strconv" "strconv"
"github.com/holiman/uint256"
) )
var ( var (
@ -30,6 +32,7 @@ var (
bigT = reflect.TypeOf((*Big)(nil)) bigT = reflect.TypeOf((*Big)(nil))
uintT = reflect.TypeOf(Uint(0)) uintT = reflect.TypeOf(Uint(0))
uint64T = reflect.TypeOf(Uint64(0)) uint64T = reflect.TypeOf(Uint64(0))
u256T = reflect.TypeOf((*uint256.Int)(nil))
) )
// Bytes marshals/unmarshals as a JSON string with 0x prefix. // Bytes marshals/unmarshals as a JSON string with 0x prefix.
@ -225,6 +228,48 @@ func (b *Big) UnmarshalGraphQL(input interface{}) error {
return err return err
} }
// U256 marshals/unmarshals as a JSON string with 0x prefix.
// The zero value marshals as "0x0".
type U256 uint256.Int
// MarshalText implements encoding.TextMarshaler
func (b U256) MarshalText() ([]byte, error) {
u256 := (*uint256.Int)(&b)
return []byte(u256.Hex()), nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (b *U256) UnmarshalJSON(input []byte) error {
// The uint256.Int.UnmarshalJSON method accepts "dec", "0xhex"; we must be
// more strict, hence we check string and invoke SetFromHex directly.
if !isString(input) {
return errNonString(u256T)
}
// The hex decoder needs to accept empty string ("") as '0', which uint256.Int
// would reject.
if len(input) == 2 {
(*uint256.Int)(b).Clear()
return nil
}
err := (*uint256.Int)(b).SetFromHex(string(input[1 : len(input)-1]))
if err != nil {
return &json.UnmarshalTypeError{Value: err.Error(), Type: u256T}
}
return nil
}
// UnmarshalText implements encoding.TextUnmarshaler
func (b *U256) UnmarshalText(input []byte) error {
// The uint256.Int.UnmarshalText method accepts "dec", "0xhex"; we must be
// more strict, hence we check string and invoke SetFromHex directly.
return (*uint256.Int)(b).SetFromHex(string(input))
}
// String returns the hex encoding of b.
func (b *U256) String() string {
return (*uint256.Int)(b).Hex()
}
// Uint64 marshals/unmarshals as a JSON string with 0x prefix. // Uint64 marshals/unmarshals as a JSON string with 0x prefix.
// The zero value marshals as "0x0". // The zero value marshals as "0x0".
type Uint64 uint64 type Uint64 uint64

View file

@ -23,6 +23,8 @@ import (
"errors" "errors"
"math/big" "math/big"
"testing" "testing"
"github.com/holiman/uint256"
) )
func checkError(t *testing.T, input string, got, want error) bool { func checkError(t *testing.T, input string, got, want error) bool {
@ -176,6 +178,64 @@ func TestUnmarshalBig(t *testing.T) {
} }
} }
var unmarshalU256Tests = []unmarshalTest{
// invalid encoding
{input: "", wantErr: errJSONEOF},
{input: "null", wantErr: errNonString(u256T)},
{input: "10", wantErr: errNonString(u256T)},
{input: `"0"`, wantErr: wrapTypeError(ErrMissingPrefix, u256T)},
{input: `"0x"`, wantErr: wrapTypeError(ErrEmptyNumber, u256T)},
{input: `"0x01"`, wantErr: wrapTypeError(ErrLeadingZero, u256T)},
{input: `"0xx"`, wantErr: wrapTypeError(ErrSyntax, u256T)},
{input: `"0x1zz01"`, wantErr: wrapTypeError(ErrSyntax, u256T)},
{
input: `"0x10000000000000000000000000000000000000000000000000000000000000000"`,
wantErr: wrapTypeError(ErrBig256Range, u256T),
},
// valid encoding
{input: `""`, want: big.NewInt(0)},
{input: `"0x0"`, want: big.NewInt(0)},
{input: `"0x2"`, want: big.NewInt(0x2)},
{input: `"0x2F2"`, want: big.NewInt(0x2f2)},
{input: `"0X2F2"`, want: big.NewInt(0x2f2)},
{input: `"0x1122aaff"`, want: big.NewInt(0x1122aaff)},
{input: `"0xbBb"`, want: big.NewInt(0xbbb)},
{input: `"0xfffffffff"`, want: big.NewInt(0xfffffffff)},
{
input: `"0x112233445566778899aabbccddeeff"`,
want: referenceBig("112233445566778899aabbccddeeff"),
},
{
input: `"0xffffffffffffffffffffffffffffffffffff"`,
want: referenceBig("ffffffffffffffffffffffffffffffffffff"),
},
{
input: `"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"`,
want: referenceBig("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
},
}
func TestUnmarshalU256(t *testing.T) {
for _, test := range unmarshalU256Tests {
var v U256
err := json.Unmarshal([]byte(test.input), &v)
if !checkError(t, test.input, err, test.wantErr) {
continue
}
if test.want == nil {
continue
}
want := new(uint256.Int)
want.SetFromBig(test.want.(*big.Int))
have := (*uint256.Int)(&v)
if want.Cmp(have) != 0 {
t.Errorf("input %s: value mismatch: have %x, want %x", test.input, have, want)
continue
}
}
}
func BenchmarkUnmarshalBig(b *testing.B) { func BenchmarkUnmarshalBig(b *testing.B) {
input := []byte(`"0x123456789abcdef123456789abcdef"`) input := []byte(`"0x123456789abcdef123456789abcdef"`)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {

View file

@ -302,9 +302,22 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
if chain.Config().IsShanghai(header.Number, header.Time) { if chain.Config().IsShanghai(header.Number, header.Time) {
return errors.New("clique does not support shanghai fork") return errors.New("clique does not support shanghai fork")
} }
// Verify the non-existence of withdrawalsHash.
if header.WithdrawalsHash != nil {
return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
}
if chain.Config().IsCancun(header.Number, header.Time) { if chain.Config().IsCancun(header.Number, header.Time) {
return errors.New("clique does not support cancun fork") return errors.New("clique does not support cancun fork")
} }
// Verify the non-existence of cancun-specific header fields
switch {
case header.ExcessBlobGas != nil:
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
case header.BlobGasUsed != nil:
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
case header.ParentBeaconRoot != nil:
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
}
// All basic checks passed, verify cascading fields // All basic checks passed, verify cascading fields
return c.verifyCascadingFields(chain, header, parents) return c.verifyCascadingFields(chain, header, parents)
} }
@ -753,6 +766,15 @@ func encodeSigHeader(w io.Writer, header *types.Header) {
if header.WithdrawalsHash != nil { if header.WithdrawalsHash != nil {
panic("unexpected withdrawal hash value in clique") panic("unexpected withdrawal hash value in clique")
} }
if header.ExcessBlobGas != nil {
panic("unexpected excess blob gas value in clique")
}
if header.BlobGasUsed != nil {
panic("unexpected blob gas used value in clique")
}
if header.ParentBeaconRoot != nil {
panic("unexpected parent beacon root value in clique")
}
if err := rlp.Encode(w, enc); err != nil { if err := rlp.Encode(w, enc); err != nil {
panic("can't encode: " + err.Error()) panic("can't encode: " + err.Error())
} }

View file

@ -266,9 +266,22 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa
if chain.Config().IsShanghai(header.Number, header.Time) { if chain.Config().IsShanghai(header.Number, header.Time) {
return errors.New("ethash does not support shanghai fork") return errors.New("ethash does not support shanghai fork")
} }
// Verify the non-existence of withdrawalsHash.
if header.WithdrawalsHash != nil {
return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
}
if chain.Config().IsCancun(header.Number, header.Time) { if chain.Config().IsCancun(header.Number, header.Time) {
return errors.New("ethash does not support cancun fork") return errors.New("ethash does not support cancun fork")
} }
// Verify the non-existence of cancun-specific header fields
switch {
case header.ExcessBlobGas != nil:
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
case header.BlobGasUsed != nil:
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
case header.ParentBeaconRoot != nil:
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
}
// Add some fake checks for tests // Add some fake checks for tests
if ethash.fakeDelay != nil { if ethash.fakeDelay != nil {
time.Sleep(*ethash.fakeDelay) time.Sleep(*ethash.fakeDelay)
@ -533,6 +546,15 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
if header.WithdrawalsHash != nil { if header.WithdrawalsHash != nil {
panic("withdrawal hash set on ethash") panic("withdrawal hash set on ethash")
} }
if header.ExcessBlobGas != nil {
panic("excess blob gas set on ethash")
}
if header.BlobGasUsed != nil {
panic("blob gas used set on ethash")
}
if header.ParentBeaconRoot != nil {
panic("parent beacon root set on ethash")
}
rlp.Encode(hasher, enc) rlp.Encode(hasher, enc)
hasher.Sum(hash[:0]) hasher.Sum(hash[:0])
return hash return hash
@ -564,10 +586,10 @@ func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, heade
r.Sub(r, header.Number) r.Sub(r, header.Number)
r.Mul(r, blockReward) r.Mul(r, blockReward)
r.Div(r, big8) r.Div(r, big8)
stateDB.AddBalance(uncle.Coinbase, r, state.BalanceChangeRewardMineUncle) stateDB.AddBalance(uncle.Coinbase, r, state.BalanceIncreaseRewardMineUncle)
r.Div(blockReward, big32) r.Div(blockReward, big32)
reward.Add(reward, r) reward.Add(reward, r)
} }
stateDB.AddBalance(header.Coinbase, reward, state.BalanceChangeRewardMineBlock) stateDB.AddBalance(header.Coinbase, reward, state.BalanceIncreaseRewardMineBlock)
} }

View file

@ -80,7 +80,7 @@ func ApplyDAOHardFork(statedb *state.StateDB) {
// Move every DAO account and extra-balance account funds into the refund contract // Move every DAO account and extra-balance account funds into the refund contract
for _, addr := range params.DAODrainList() { for _, addr := range params.DAODrainList() {
statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), state.BalanceChangeDaoRefundContract) statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), state.BalanceIncreaseDaoContract)
statedb.SetBalance(addr, new(big.Int), state.BalanceChangeDaoAdjustBalance) statedb.SetBalance(addr, new(big.Int), state.BalanceDecreaseDaoAccount)
} }
} }

View file

@ -192,7 +192,7 @@ type BlockchainLogger interface {
state.StateLogger state.StateLogger
// OnBlockStart is called before executing `block`. // OnBlockStart is called before executing `block`.
// `td` is the total difficulty prior to `block`. // `td` is the total difficulty prior to `block`.
OnBlockStart(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header) OnBlockStart(block *types.Block, td *big.Int, finalized *types.Header, safe *types.Header, chainConfig *params.ChainConfig)
OnBlockEnd(err error) OnBlockEnd(err error)
OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc) OnGenesisBlock(genesis *types.Block, alloc GenesisAlloc)
OnBeaconBlockRootStart(root common.Hash) OnBeaconBlockRootStart(root common.Hash)
@ -295,7 +295,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
// Setup the genesis block, commit the provided genesis specification // Setup the genesis block, commit the provided genesis specification
// to database if the genesis block is not present yet, or load the // to database if the genesis block is not present yet, or load the
// stored one from database. // stored one from database.
chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides, logger) chainConfig, genesisHash, genesisErr := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides)
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
return nil, genesisErr return nil, genesisErr
} }
@ -1804,7 +1804,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
} }
stats.processed++ stats.processed++
if bc.logger != nil { if bc.logger != nil {
bc.logger.OnBlockStart(block, bc.GetTd(block.ParentHash(), block.NumberU64()-1), bc.CurrentFinalBlock(), bc.CurrentSafeBlock()) bc.logger.OnBlockStart(block, bc.GetTd(block.ParentHash(), block.NumberU64()-1), bc.CurrentFinalBlock(), bc.CurrentSafeBlock(), bc.chainConfig)
bc.logger.OnBlockEnd(nil) bc.logger.OnBlockEnd(nil)
} }
@ -1932,7 +1932,7 @@ type blockProcessingResult struct {
func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, followupInterrupt *atomic.Bool, start time.Time, setHead bool) (blockEndErr error, _ bool, _ *blockProcessingResult) { func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, followupInterrupt *atomic.Bool, start time.Time, setHead bool) (blockEndErr error, _ bool, _ *blockProcessingResult) {
if bc.logger != nil { if bc.logger != nil {
td := bc.GetTd(block.ParentHash(), block.NumberU64()-1) td := bc.GetTd(block.ParentHash(), block.NumberU64()-1)
bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock()) bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock(), bc.chainConfig)
defer func() { defer func() {
bc.logger.OnBlockEnd(blockEndErr) bc.logger.OnBlockEnd(blockEndErr)
}() }()

View file

@ -409,7 +409,7 @@ func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int,
triedb := trie.NewDatabase(db, trie.HashDefaults) triedb := trie.NewDatabase(db, trie.HashDefaults)
defer triedb.Close() defer triedb.Close()
_, err := genesis.Commit(db, triedb, nil) _, err := genesis.Commit(db, triedb)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View file

@ -142,7 +142,7 @@ func (ga *GenesisAlloc) hash(isVerkle bool) (common.Hash, error) {
} }
for addr, account := range *ga { for addr, account := range *ga {
if account.Balance != nil { if account.Balance != nil {
statedb.AddBalance(addr, account.Balance, state.BalanceChangeGenesisBalance) statedb.AddBalance(addr, account.Balance, state.BalanceIncreaseGenesisBalance)
} }
statedb.SetCode(addr, account.Code) statedb.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce) statedb.SetNonce(addr, account.Nonce)
@ -156,14 +156,16 @@ func (ga *GenesisAlloc) hash(isVerkle bool) (common.Hash, error) {
// flush is very similar with hash, but the main difference is all the generated // flush is very similar with hash, but the main difference is all the generated
// states will be persisted into the given database. Also, the genesis state // states will be persisted into the given database. Also, the genesis state
// specification will be flushed as well. // specification will be flushed as well.
func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash, bcLogger BlockchainLogger) error { func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error {
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil) statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
if err != nil { if err != nil {
return err return err
} }
for addr, account := range *ga { for addr, account := range *ga {
if account.Balance != nil { if account.Balance != nil {
statedb.AddBalance(addr, account.Balance, state.BalanceChangeGenesisBalance) // This is not actually logged via tracer because OnGenesisBlock
// already captures the allocations.
statedb.AddBalance(addr, account.Balance, state.BalanceIncreaseGenesisBalance)
} }
statedb.SetCode(addr, account.Code) statedb.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce) statedb.SetNonce(addr, account.Nonce)
@ -305,10 +307,10 @@ type ChainOverrides struct {
// //
// The returned chain configuration is never nil. // The returned chain configuration is never nil.
func SetupGenesisBlock(db ethdb.Database, triedb *trie.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) { func SetupGenesisBlock(db ethdb.Database, triedb *trie.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) {
return SetupGenesisBlockWithOverride(db, triedb, genesis, nil, nil) return SetupGenesisBlockWithOverride(db, triedb, genesis, nil)
} }
func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, genesis *Genesis, overrides *ChainOverrides, bcLogger BlockchainLogger) (*params.ChainConfig, common.Hash, error) { func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, error) {
if genesis != nil && genesis.Config == nil { if genesis != nil && genesis.Config == nil {
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
} }
@ -333,7 +335,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
} }
applyOverrides(genesis.Config) applyOverrides(genesis.Config)
block, err := genesis.Commit(db, triedb, bcLogger) block, err := genesis.Commit(db, triedb)
if err != nil { if err != nil {
return genesis.Config, common.Hash{}, err return genesis.Config, common.Hash{}, err
} }
@ -354,7 +356,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *trie.Database, gen
if hash != stored { if hash != stored {
return genesis.Config, hash, &GenesisMismatchError{stored, hash} return genesis.Config, hash, &GenesisMismatchError{stored, hash}
} }
block, err := genesis.Commit(db, triedb, bcLogger) block, err := genesis.Commit(db, triedb)
if err != nil { if err != nil {
return genesis.Config, hash, err return genesis.Config, hash, err
} }
@ -522,7 +524,7 @@ func (g *Genesis) ToBlock() *types.Block {
// Commit writes the block and state of a genesis specification to the database. // Commit writes the block and state of a genesis specification to the database.
// The block is committed as the canonical head block. // The block is committed as the canonical head block.
func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database, bcLogger BlockchainLogger) (*types.Block, error) { func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block, error) {
block := g.ToBlock() block := g.ToBlock()
if block.Number().Sign() != 0 { if block.Number().Sign() != 0 {
return nil, errors.New("can't commit genesis block with number > 0") return nil, errors.New("can't commit genesis block with number > 0")
@ -537,13 +539,10 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database, bcLogger Bloc
if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength { if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength {
return nil, errors.New("can't start clique chain without signers") return nil, errors.New("can't start clique chain without signers")
} }
if bcLogger != nil {
bcLogger.OnGenesisBlock(block, g.Alloc)
}
// All the checks has passed, flush the states derived from the genesis // All the checks has passed, flush the states derived from the genesis
// specification as well as the specification itself into the provided // specification as well as the specification itself into the provided
// database. // database.
if err := g.Alloc.flush(db, triedb, block.Hash(), bcLogger); err != nil { if err := g.Alloc.flush(db, triedb, block.Hash()); err != nil {
return nil, err return nil, err
} }
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty())
@ -562,7 +561,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database, bcLogger Bloc
// Note the state changes will be committed in hash-based scheme, use Commit // Note the state changes will be committed in hash-based scheme, use Commit
// if path-scheme is preferred. // if path-scheme is preferred.
func (g *Genesis) MustCommit(db ethdb.Database, triedb *trie.Database) *types.Block { func (g *Genesis) MustCommit(db ethdb.Database, triedb *trie.Database) *types.Block {
block, err := g.Commit(db, triedb, nil) block, err := g.Commit(db, triedb)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View file

@ -38,7 +38,7 @@ func TestInvalidCliqueConfig(t *testing.T) {
block := DefaultGoerliGenesisBlock() block := DefaultGoerliGenesisBlock()
block.ExtraData = []byte{} block.ExtraData = []byte{}
db := rawdb.NewMemoryDatabase() db := rawdb.NewMemoryDatabase()
if _, err := block.Commit(db, trie.NewDatabase(db, nil), nil); err == nil { if _, err := block.Commit(db, trie.NewDatabase(db, nil)); err == nil {
t.Fatal("Expected error on invalid clique config") t.Fatal("Expected error on invalid clique config")
} }
} }
@ -97,7 +97,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
name: "custom block in DB, genesis == nil", name: "custom block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
tdb := trie.NewDatabase(db, newDbConfig(scheme)) tdb := trie.NewDatabase(db, newDbConfig(scheme))
customg.Commit(db, tdb, nil) customg.Commit(db, tdb)
return SetupGenesisBlock(db, tdb, nil) return SetupGenesisBlock(db, tdb, nil)
}, },
wantHash: customghash, wantHash: customghash,
@ -107,7 +107,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
name: "custom block in DB, genesis == goerli", name: "custom block in DB, genesis == goerli",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
tdb := trie.NewDatabase(db, newDbConfig(scheme)) tdb := trie.NewDatabase(db, newDbConfig(scheme))
customg.Commit(db, tdb, nil) customg.Commit(db, tdb)
return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock()) return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock())
}, },
wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash}, wantErr: &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash},
@ -118,7 +118,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
name: "compatible config in DB", name: "compatible config in DB",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
tdb := trie.NewDatabase(db, newDbConfig(scheme)) tdb := trie.NewDatabase(db, newDbConfig(scheme))
oldcustomg.Commit(db, tdb, nil) oldcustomg.Commit(db, tdb)
return SetupGenesisBlock(db, tdb, &customg) return SetupGenesisBlock(db, tdb, &customg)
}, },
wantHash: customghash, wantHash: customghash,
@ -130,7 +130,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
// Commit the 'old' genesis block with Homestead transition at #2. // Commit the 'old' genesis block with Homestead transition at #2.
// Advance to block #4, past the homestead transition block of customg. // Advance to block #4, past the homestead transition block of customg.
tdb := trie.NewDatabase(db, newDbConfig(scheme)) tdb := trie.NewDatabase(db, newDbConfig(scheme))
oldcustomg.Commit(db, tdb, nil) oldcustomg.Commit(db, tdb)
bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil) bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil)
defer bc.Stop() defer bc.Stop()

View file

@ -73,7 +73,7 @@ func TestHeaderInsertion(t *testing.T) {
db = rawdb.NewMemoryDatabase() db = rawdb.NewMemoryDatabase()
gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges} gspec = &Genesis{BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges}
) )
gspec.Commit(db, trie.NewDatabase(db, nil), nil) gspec.Commit(db, trie.NewDatabase(db, nil))
hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false }) hc, err := NewHeaderChain(db, gspec.Config, ethash.NewFaker(), func() bool { return false })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -49,21 +49,24 @@ type DumpCollector interface {
// DumpAccount represents an account in the state. // DumpAccount represents an account in the state.
type DumpAccount struct { type DumpAccount struct {
Balance string `json:"balance"` Balance string `json:"balance"`
Nonce uint64 `json:"nonce"` Nonce uint64 `json:"nonce"`
Root hexutil.Bytes `json:"root"` Root hexutil.Bytes `json:"root"`
CodeHash hexutil.Bytes `json:"codeHash"` CodeHash hexutil.Bytes `json:"codeHash"`
Code hexutil.Bytes `json:"code,omitempty"` Code hexutil.Bytes `json:"code,omitempty"`
Storage map[common.Hash]string `json:"storage,omitempty"` Storage map[common.Hash]string `json:"storage,omitempty"`
Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode
SecureKey hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key AddressHash hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key
} }
// Dump represents the full dump in a collected format, as one large map. // Dump represents the full dump in a collected format, as one large map.
type Dump struct { type Dump struct {
Root string `json:"root"` Root string `json:"root"`
Accounts map[common.Address]DumpAccount `json:"accounts"` Accounts map[string]DumpAccount `json:"accounts"`
// Next can be set to represent that this dump is only partial, and Next
// is where an iterator should be positioned in order to continue the dump.
Next []byte `json:"next,omitempty"` // nil if no more accounts
} }
// OnRoot implements DumpCollector interface // OnRoot implements DumpCollector interface
@ -73,27 +76,11 @@ func (d *Dump) OnRoot(root common.Hash) {
// OnAccount implements DumpCollector interface // OnAccount implements DumpCollector interface
func (d *Dump) OnAccount(addr *common.Address, account DumpAccount) { func (d *Dump) OnAccount(addr *common.Address, account DumpAccount) {
if addr != nil { if addr == nil {
d.Accounts[*addr] = account d.Accounts[fmt.Sprintf("pre(%s)", account.AddressHash)] = account
} }
}
// IteratorDump is an implementation for iterating over data.
type IteratorDump struct {
Root string `json:"root"`
Accounts map[common.Address]DumpAccount `json:"accounts"`
Next []byte `json:"next,omitempty"` // nil if no more accounts
}
// OnRoot implements DumpCollector interface
func (d *IteratorDump) OnRoot(root common.Hash) {
d.Root = fmt.Sprintf("%x", root)
}
// OnAccount implements DumpCollector interface
func (d *IteratorDump) OnAccount(addr *common.Address, account DumpAccount) {
if addr != nil { if addr != nil {
d.Accounts[*addr] = account d.Accounts[(*addr).String()] = account
} }
} }
@ -105,14 +92,14 @@ type iterativeDump struct {
// OnAccount implements DumpCollector interface // OnAccount implements DumpCollector interface
func (d iterativeDump) OnAccount(addr *common.Address, account DumpAccount) { func (d iterativeDump) OnAccount(addr *common.Address, account DumpAccount) {
dumpAccount := &DumpAccount{ dumpAccount := &DumpAccount{
Balance: account.Balance, Balance: account.Balance,
Nonce: account.Nonce, Nonce: account.Nonce,
Root: account.Root, Root: account.Root,
CodeHash: account.CodeHash, CodeHash: account.CodeHash,
Code: account.Code, Code: account.Code,
Storage: account.Storage, Storage: account.Storage,
SecureKey: account.SecureKey, AddressHash: account.AddressHash,
Address: addr, Address: addr,
} }
d.Encode(dumpAccount) d.Encode(dumpAccount)
} }
@ -150,26 +137,27 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
if err := rlp.DecodeBytes(it.Value, &data); err != nil { if err := rlp.DecodeBytes(it.Value, &data); err != nil {
panic(err) panic(err)
} }
account := DumpAccount{
Balance: data.Balance.String(),
Nonce: data.Nonce,
Root: data.Root[:],
CodeHash: data.CodeHash,
SecureKey: it.Key,
}
var ( var (
addrBytes = s.trie.GetKey(it.Key) account = DumpAccount{
addr = common.BytesToAddress(addrBytes) Balance: data.Balance.String(),
Nonce: data.Nonce,
Root: data.Root[:],
CodeHash: data.CodeHash,
AddressHash: it.Key,
}
address *common.Address address *common.Address
addr common.Address
addrBytes = s.trie.GetKey(it.Key)
) )
if addrBytes == nil { if addrBytes == nil {
// Preimage missing
missingPreimages++ missingPreimages++
if conf.OnlyWithAddresses { if conf.OnlyWithAddresses {
continue continue
} }
} else { } else {
addr = common.BytesToAddress(addrBytes)
address = &addr address = &addr
account.Address = address
} }
obj := newObject(s, addr, &data) obj := newObject(s, addr, &data)
if !conf.SkipCode { if !conf.SkipCode {
@ -220,12 +208,13 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
return nextKey return nextKey
} }
// RawDump returns the entire state an a single large object // RawDump returns the state. If the processing is aborted e.g. due to options
// reaching Max, the `Next` key is set on the returned Dump.
func (s *StateDB) RawDump(opts *DumpConfig) Dump { func (s *StateDB) RawDump(opts *DumpConfig) Dump {
dump := &Dump{ dump := &Dump{
Accounts: make(map[common.Address]DumpAccount), Accounts: make(map[string]DumpAccount),
} }
s.DumpToCollector(dump, opts) dump.Next = s.DumpToCollector(dump, opts)
return *dump return *dump
} }
@ -234,7 +223,7 @@ func (s *StateDB) Dump(opts *DumpConfig) []byte {
dump := s.RawDump(opts) dump := s.RawDump(opts)
json, err := json.MarshalIndent(dump, "", " ") json, err := json.MarshalIndent(dump, "", " ")
if err != nil { if err != nil {
fmt.Println("Dump err", err) log.Error("Error dumping state", "err", err)
} }
return json return json
} }
@ -243,12 +232,3 @@ func (s *StateDB) Dump(opts *DumpConfig) []byte {
func (s *StateDB) IterativeDump(opts *DumpConfig, output *json.Encoder) { func (s *StateDB) IterativeDump(opts *DumpConfig, output *json.Encoder) {
s.DumpToCollector(iterativeDump{output}, opts) s.DumpToCollector(iterativeDump{output}, opts)
} }
// IteratorDump dumps out a batch of accounts starts with the given start key
func (s *StateDB) IteratorDump(opts *DumpConfig) IteratorDump {
iterator := &IteratorDump{
Accounts: make(map[common.Address]DumpAccount),
}
iterator.Next = s.DumpToCollector(iterator, opts)
return *iterator
}

View file

@ -21,19 +21,48 @@ package state
type BalanceChangeReason byte type BalanceChangeReason byte
const ( const (
BalanceChangeUnspecified BalanceChangeReason = iota BalanceChangeUnspecified BalanceChangeReason = 0
BalanceChangeRewardMineUncle
BalanceChangeRewardMineBlock // Issuance
BalanceChangeDaoRefundContract // BalanceIncreaseRewardMineUncle is a reward for mining an uncle block.
BalanceChangeDaoAdjustBalance BalanceIncreaseRewardMineUncle BalanceChangeReason = 1
BalanceChangeTransfer // BalanceIncreaseRewardMineBlock is a reward for mining a block.
BalanceChangeGenesisBalance BalanceIncreaseRewardMineBlock BalanceChangeReason = 2
BalanceChangeGasBuy // BalanceIncreaseWithdrawal is ether withdrawn from the beacon chain.
BalanceChangeRewardTransactionFee BalanceChangeWithdrawal BalanceChangeReason = 3
BalanceChangeGasRefund // BalanceIncreaseGenesisBalance is ether allocated at the genesis block.
BalanceChangeTouchAccount BalanceIncreaseGenesisBalance BalanceChangeReason = 4
BalanceChangeSuicideRefund
BalanceChangeSuicideWithdraw // Transaction fees
BalanceChangeBurn // BalanceIncreaseRewardTransactionFee is the transaction tip increasing block builder's balance.
BalanceChangeWithdrawal BalanceIncreaseRewardTransactionFee BalanceChangeReason = 5
// BalanceDecreaseGasBuy is spent to purchase gas for execution a transaction.
// Part of this gas will be burnt as per EIP-1559 rules.
BalanceDecreaseGasBuy BalanceChangeReason = 6
// BalanceIncreaseGasReturn is ether returned for unused gas at the end of execution.
BalanceIncreaseGasReturn BalanceChangeReason = 7
// DAO fork
// BalanceIncreaseDaoContract is ether sent to the DAO refund contract.
BalanceIncreaseDaoContract BalanceChangeReason = 8
// BalanceDecreaseDaoAccount is ether taken from a DAO account to be moved to the refund contract.
BalanceDecreaseDaoAccount BalanceChangeReason = 9
// BalanceChangeTransfer is ether transfered via a call.
// it is a decrease for the sender and an increase for the recipient.
BalanceChangeTransfer BalanceChangeReason = 10
// BalanceChangeTouchAccount is a transfer of zero value. It is only there to
// touch-create an account.
BalanceChangeTouchAccount BalanceChangeReason = 11
// BalanceIncreaseSelfdestruct is added to the recipient as indicated by a selfdestructing account.
BalanceIncreaseSelfdestruct BalanceChangeReason = 12
// BalanceDecreaseSelfdestruct is deducted from a contract due to self-destruct.
// This can happen either at the point of self-destruction, or at the end of the tx
// if ether was sent to contract post-selfdestruct.
BalanceDecreaseSelfdestruct BalanceChangeReason = 13
// BalanceDecreaseSelfdestructBurn is ether that is sent to an already self-destructed
// account within the same tx (captured at end of tx).
// Note it doesn't account for a self-destruct which appoints itself as recipient.
BalanceDecreaseSelfdestructBurn BalanceChangeReason = 14
) )

View file

@ -601,7 +601,7 @@ func testGenerateWithExtraAccounts(t *testing.T, scheme string) {
} }
func enableLogging() { func enableLogging() {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
} }
// Tests that snapshot generation when an extra account with storage exists in the snap state. // Tests that snapshot generation when an extra account with storage exists in the snap state.

View file

@ -98,7 +98,10 @@ func (s *stateObject) empty() bool {
// newObject creates a state object. // newObject creates a state object.
func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject { func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject {
origin := acct var (
origin = acct
created = acct == nil // true if the account was not existent
)
if acct == nil { if acct == nil {
acct = types.NewEmptyStateAccount() acct = types.NewEmptyStateAccount()
} }
@ -111,6 +114,7 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s
originStorage: make(Storage), originStorage: make(Storage),
pendingStorage: make(Storage), pendingStorage: make(Storage),
dirtyStorage: make(Storage), dirtyStorage: make(Storage),
created: created,
} }
} }

View file

@ -71,6 +71,7 @@ func TestDump(t *testing.T) {
"nonce": 0, "nonce": 0,
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
"address": "0x0000000000000000000000000000000000000001",
"key": "0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d" "key": "0x1468288056310c82aa4c01a7e12a10f8111a0560e72b700555479031b86c357d"
}, },
"0x0000000000000000000000000000000000000002": { "0x0000000000000000000000000000000000000002": {
@ -78,6 +79,7 @@ func TestDump(t *testing.T) {
"nonce": 0, "nonce": 0,
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
"address": "0x0000000000000000000000000000000000000002",
"key": "0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62" "key": "0xd52688a8f926c816ca1e079067caba944f158e764817b83fc43594370ca9cf62"
}, },
"0x0000000000000000000000000000000000000102": { "0x0000000000000000000000000000000000000102": {
@ -86,6 +88,7 @@ func TestDump(t *testing.T) {
"root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"codeHash": "0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3", "codeHash": "0x87874902497a5bb968da31a2998d8f22e949d1ef6214bcdedd8bae24cca4b9e3",
"code": "0x03030303030303", "code": "0x03030303030303",
"address": "0x0000000000000000000000000000000000000102",
"key": "0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1" "key": "0xa17eacbc25cda025e81db9c5c62868822c73ce097cee2a63e33a2e41268358a1"
} }
} }

View file

@ -60,7 +60,6 @@ type StateLogger interface {
OnStorageChange(addr common.Address, slot common.Hash, prev, new common.Hash) OnStorageChange(addr common.Address, slot common.Hash, prev, new common.Hash)
OnLog(log *types.Log) OnLog(log *types.Log)
// OnNewAccount is called when a new account is created. // OnNewAccount is called when a new account is created.
// Note: it will be even invoked when precompiled contracts are populated.
OnNewAccount(addr common.Address) OnNewAccount(addr common.Address)
} }
@ -477,13 +476,20 @@ func (s *StateDB) SelfDestruct(addr common.Address) {
if stateObject == nil { if stateObject == nil {
return return
} }
var (
prev = new(big.Int).Set(stateObject.Balance())
n = new(big.Int)
)
s.journal.append(selfDestructChange{ s.journal.append(selfDestructChange{
account: &addr, account: &addr,
prev: stateObject.selfDestructed, prev: stateObject.selfDestructed,
prevbalance: new(big.Int).Set(stateObject.Balance()), prevbalance: prev,
}) })
if s.logger != nil {
s.logger.OnBalanceChange(addr, prev, n, BalanceDecreaseSelfdestruct)
}
stateObject.markSelfdestructed() stateObject.markSelfdestructed()
stateObject.data.Balance = new(big.Int) stateObject.data.Balance = n
} }
func (s *StateDB) Selfdestruct6780(addr common.Address) { func (s *StateDB) Selfdestruct6780(addr common.Address) {
@ -695,9 +701,6 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
delete(s.accountsOrigin, prev.address) delete(s.accountsOrigin, prev.address)
delete(s.storagesOrigin, prev.address) delete(s.storagesOrigin, prev.address)
} }
newobj.created = true
s.setStateObject(newobj) s.setStateObject(newobj)
if prev != nil && !prev.deleted { if prev != nil && !prev.deleted {
return newobj, prev return newobj, prev
@ -874,6 +877,10 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) { if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) {
obj.deleted = true obj.deleted = true
// If ether was sent to account post-selfdestruct it is burnt.
if bal := obj.Balance(); bal.Sign() != 0 && s.logger != nil {
s.logger.OnBalanceChange(obj.address, bal, new(big.Int), BalanceDecreaseSelfdestructBurn)
}
// We need to maintain account deletions explicitly (will remain // We need to maintain account deletions explicitly (will remain
// set indefinitely). Note only the first occurred self-destruct // set indefinitely). Note only the first occurred self-destruct
// event is tracked. // event is tracked.

View file

@ -33,9 +33,10 @@ import (
// ExecutionResult includes all output after executing given evm // ExecutionResult includes all output after executing given evm
// message no matter the execution itself is successful or not. // message no matter the execution itself is successful or not.
type ExecutionResult struct { type ExecutionResult struct {
UsedGas uint64 // Total used gas but include the refunded gas UsedGas uint64 // Total used gas, not including the refunded gas
Err error // Any error encountered during the execution(listed in core/vm/errors.go) RefundedGas uint64 // Total gas refunded after execution
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode) Err error // Any error encountered during the execution(listed in core/vm/errors.go)
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
} }
// Unwrap returns the internal evm error which allows us for further // Unwrap returns the internal evm error which allows us for further
@ -139,6 +140,8 @@ type Message struct {
AccessList types.AccessList AccessList types.AccessList
BlobGasFeeCap *big.Int BlobGasFeeCap *big.Int
BlobHashes []common.Hash BlobHashes []common.Hash
// Distinguishes type-2 txes
DynamicFee bool
// When SkipAccountChecks is true, the message nonce is not checked against the // When SkipAccountChecks is true, the message nonce is not checked against the
// account nonce in state. It also disables checking that the sender is an EOA. // account nonce in state. It also disables checking that the sender is an EOA.
@ -161,6 +164,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
SkipAccountChecks: false, SkipAccountChecks: false,
BlobHashes: tx.BlobHashes(), BlobHashes: tx.BlobHashes(),
BlobGasFeeCap: tx.BlobGasFeeCap(), BlobGasFeeCap: tx.BlobGasFeeCap(),
DynamicFee: tx.Type() == 2 || tx.Type() == 3,
} }
// If baseFee provided, set gasPrice to effectiveGasPrice. // If baseFee provided, set gasPrice to effectiveGasPrice.
if baseFee != nil { if baseFee != nil {
@ -266,7 +270,7 @@ func (st *StateTransition) buyGas() error {
st.gasRemaining += st.msg.GasLimit st.gasRemaining += st.msg.GasLimit
st.initialGas = st.msg.GasLimit st.initialGas = st.msg.GasLimit
st.state.SubBalance(st.msg.From, mgval, state.BalanceChangeGasBuy) st.state.SubBalance(st.msg.From, mgval, state.BalanceDecreaseGasBuy)
return nil return nil
} }
@ -421,12 +425,13 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value) ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value)
} }
var gasRefund uint64
if !rules.IsLondon { if !rules.IsLondon {
// Before EIP-3529: refunds were capped to gasUsed / 2 // Before EIP-3529: refunds were capped to gasUsed / 2
st.refundGas(params.RefundQuotient) gasRefund = st.refundGas(params.RefundQuotient)
} else { } else {
// After EIP-3529: refunds are capped to gasUsed / 5 // After EIP-3529: refunds are capped to gasUsed / 5
st.refundGas(params.RefundQuotientEIP3529) gasRefund = st.refundGas(params.RefundQuotientEIP3529)
} }
effectiveTip := msg.GasPrice effectiveTip := msg.GasPrice
if rules.IsLondon { if rules.IsLondon {
@ -440,17 +445,18 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
} else { } else {
fee := new(big.Int).SetUint64(st.gasUsed()) fee := new(big.Int).SetUint64(st.gasUsed())
fee.Mul(fee, effectiveTip) fee.Mul(fee, effectiveTip)
st.state.AddBalance(st.evm.Context.Coinbase, fee, state.BalanceChangeRewardTransactionFee) st.state.AddBalance(st.evm.Context.Coinbase, fee, state.BalanceIncreaseRewardTransactionFee)
} }
return &ExecutionResult{ return &ExecutionResult{
UsedGas: st.gasUsed(), UsedGas: st.gasUsed(),
Err: vmerr, RefundedGas: gasRefund,
ReturnData: ret, Err: vmerr,
ReturnData: ret,
}, nil }, nil
} }
func (st *StateTransition) refundGas(refundQuotient uint64) { func (st *StateTransition) refundGas(refundQuotient uint64) uint64 {
// Apply refund counter, capped to a refund quotient // Apply refund counter, capped to a refund quotient
refund := st.gasUsed() / refundQuotient refund := st.gasUsed() / refundQuotient
if refund > st.state.GetRefund() { if refund > st.state.GetRefund() {
@ -465,7 +471,7 @@ func (st *StateTransition) refundGas(refundQuotient uint64) {
// Return ETH for remaining gas, exchanged at the original rate. // Return ETH for remaining gas, exchanged at the original rate.
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice) remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice)
st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund) st.state.AddBalance(st.msg.From, remaining, state.BalanceIncreaseGasReturn)
if st.evm.Config.Tracer != nil && st.gasRemaining > 0 { if st.evm.Config.Tracer != nil && st.gasRemaining > 0 {
st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxLeftOverReturned) st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxLeftOverReturned)
@ -474,6 +480,8 @@ func (st *StateTransition) refundGas(refundQuotient uint64) {
// Also return remaining gas to the block gas counter so it is // Also return remaining gas to the block gas counter so it is
// available for the next transaction. // available for the next transaction.
st.gp.AddGas(st.gasRemaining) st.gp.AddGas(st.gasRemaining)
return refund
} }
// gasUsed returns the amount of gas used up by the state transition. // gasUsed returns the amount of gas used up by the state transition.

View file

@ -319,7 +319,7 @@ func verifyPoolInternals(t *testing.T, pool *BlobPool) {
// - 3. All transactions after a nonce gap must be dropped // - 3. All transactions after a nonce gap must be dropped
// - 4. All transactions after an underpriced one (including it) must be dropped // - 4. All transactions after an underpriced one (including it) must be dropped
func TestOpenDrops(t *testing.T) { func TestOpenDrops(t *testing.T) {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
// Create a temporary folder for the persistent backend // Create a temporary folder for the persistent backend
storage, _ := os.MkdirTemp("", "blobpool-") storage, _ := os.MkdirTemp("", "blobpool-")
@ -600,7 +600,7 @@ func TestOpenDrops(t *testing.T) {
// - 2. Eviction thresholds are calculated correctly for the sequences // - 2. Eviction thresholds are calculated correctly for the sequences
// - 3. Balance usage of an account is totals across all transactions // - 3. Balance usage of an account is totals across all transactions
func TestOpenIndex(t *testing.T) { func TestOpenIndex(t *testing.T) {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
// Create a temporary folder for the persistent backend // Create a temporary folder for the persistent backend
storage, _ := os.MkdirTemp("", "blobpool-") storage, _ := os.MkdirTemp("", "blobpool-")
@ -689,7 +689,7 @@ func TestOpenIndex(t *testing.T) {
// Tests that after indexing all the loaded transactions from disk, a price heap // Tests that after indexing all the loaded transactions from disk, a price heap
// is correctly constructed based on the head basefee and blobfee. // is correctly constructed based on the head basefee and blobfee.
func TestOpenHeap(t *testing.T) { func TestOpenHeap(t *testing.T) {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
// Create a temporary folder for the persistent backend // Create a temporary folder for the persistent backend
storage, _ := os.MkdirTemp("", "blobpool-") storage, _ := os.MkdirTemp("", "blobpool-")
@ -776,7 +776,7 @@ func TestOpenHeap(t *testing.T) {
// Tests that after the pool's previous state is loaded back, any transactions // Tests that after the pool's previous state is loaded back, any transactions
// over the new storage cap will get dropped. // over the new storage cap will get dropped.
func TestOpenCap(t *testing.T) { func TestOpenCap(t *testing.T) {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
// Create a temporary folder for the persistent backend // Create a temporary folder for the persistent backend
storage, _ := os.MkdirTemp("", "blobpool-") storage, _ := os.MkdirTemp("", "blobpool-")
@ -868,7 +868,7 @@ func TestOpenCap(t *testing.T) {
// specific to the blob pool. It does not do an exhaustive transaction validity // specific to the blob pool. It does not do an exhaustive transaction validity
// check. // check.
func TestAdd(t *testing.T) { func TestAdd(t *testing.T) {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, true)))
// seed is a helper tumpe to seed an initial state db and pool // seed is a helper tumpe to seed an initial state db and pool
type seed struct { type seed struct {

View file

@ -855,7 +855,7 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
} }
beneficiary := scope.Stack.pop() beneficiary := scope.Stack.pop()
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, state.BalanceChangeSuicideRefund) interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, state.BalanceIncreaseSelfdestruct)
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address()) interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
if tracer := interpreter.evm.Config.Tracer; tracer != nil { if tracer := interpreter.evm.Config.Tracer; tracer != nil {
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
@ -870,8 +870,8 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
} }
beneficiary := scope.Stack.pop() beneficiary := scope.Stack.pop()
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, state.BalanceChangeSuicideWithdraw) interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, state.BalanceDecreaseSelfdestruct)
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, state.BalanceChangeSuicideRefund) interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, state.BalanceIncreaseSelfdestruct)
interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address()) interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address())
if tracer := interpreter.evm.Config.Tracer; tracer != nil { if tracer := interpreter.evm.Config.Tracer; tracer != nil {
tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance) tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)

View file

@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be found in // Use of this source code is governed by a BSD-style license that can be found in
// the LICENSE file. // the LICENSE file.
//go:build !gofuzz && cgo
// +build !gofuzz,cgo
package secp256k1 package secp256k1
import ( import (

View file

@ -249,7 +249,7 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
return nil return nil
} }
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error) { func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM {
if vmConfig == nil { if vmConfig == nil {
vmConfig = b.eth.blockchain.GetVMConfig() vmConfig = b.eth.blockchain.GetVMConfig()
} }
@ -260,7 +260,7 @@ func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *st
} else { } else {
context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil)
} }
return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), state.Error return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig)
} }
func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {

View file

@ -133,7 +133,7 @@ func (api *DebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error)
const AccountRangeMaxResults = 256 const AccountRangeMaxResults = 256
// AccountRange enumerates all accounts in the given block and start point in paging request // AccountRange enumerates all accounts in the given block and start point in paging request
func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hexutil.Bytes, maxResults int, nocode, nostorage, incompletes bool) (state.IteratorDump, error) { func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hexutil.Bytes, maxResults int, nocode, nostorage, incompletes bool) (state.Dump, error) {
var stateDb *state.StateDB var stateDb *state.StateDB
var err error var err error
@ -144,7 +144,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
// the miner and operate on those // the miner and operate on those
_, stateDb = api.eth.miner.Pending() _, stateDb = api.eth.miner.Pending()
if stateDb == nil { if stateDb == nil {
return state.IteratorDump{}, errors.New("pending state is not available") return state.Dump{}, errors.New("pending state is not available")
} }
} else { } else {
var header *types.Header var header *types.Header
@ -158,29 +158,29 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
default: default:
block := api.eth.blockchain.GetBlockByNumber(uint64(number)) block := api.eth.blockchain.GetBlockByNumber(uint64(number))
if block == nil { if block == nil {
return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) return state.Dump{}, fmt.Errorf("block #%d not found", number)
} }
header = block.Header() header = block.Header()
} }
if header == nil { if header == nil {
return state.IteratorDump{}, fmt.Errorf("block #%d not found", number) return state.Dump{}, fmt.Errorf("block #%d not found", number)
} }
stateDb, err = api.eth.BlockChain().StateAt(header.Root) stateDb, err = api.eth.BlockChain().StateAt(header.Root)
if err != nil { if err != nil {
return state.IteratorDump{}, err return state.Dump{}, err
} }
} }
} else if hash, ok := blockNrOrHash.Hash(); ok { } else if hash, ok := blockNrOrHash.Hash(); ok {
block := api.eth.blockchain.GetBlockByHash(hash) block := api.eth.blockchain.GetBlockByHash(hash)
if block == nil { if block == nil {
return state.IteratorDump{}, fmt.Errorf("block %s not found", hash.Hex()) return state.Dump{}, fmt.Errorf("block %s not found", hash.Hex())
} }
stateDb, err = api.eth.BlockChain().StateAt(block.Root()) stateDb, err = api.eth.BlockChain().StateAt(block.Root())
if err != nil { if err != nil {
return state.IteratorDump{}, err return state.Dump{}, err
} }
} else { } else {
return state.IteratorDump{}, errors.New("either block number or block hash must be specified") return state.Dump{}, errors.New("either block number or block hash must be specified")
} }
opts := &state.DumpConfig{ opts := &state.DumpConfig{
@ -193,7 +193,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
if maxResults > AccountRangeMaxResults || maxResults <= 0 { if maxResults > AccountRangeMaxResults || maxResults <= 0 {
opts.Max = AccountRangeMaxResults opts.Max = AccountRangeMaxResults
} }
return stateDb.IteratorDump(opts), nil return stateDb.RawDump(opts), nil
} }
// StorageRangeResult is the result of a debug_storageRangeAt API call. // StorageRangeResult is the result of a debug_storageRangeAt API call.

View file

@ -21,6 +21,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"reflect" "reflect"
"strings"
"testing" "testing"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
@ -35,8 +36,8 @@ import (
var dumper = spew.ConfigState{Indent: " "} var dumper = spew.ConfigState{Indent: " "}
func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, start common.Hash, requestedNum int, expectedNum int) state.IteratorDump { func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, start common.Hash, requestedNum int, expectedNum int) state.Dump {
result := statedb.IteratorDump(&state.DumpConfig{ result := statedb.RawDump(&state.DumpConfig{
SkipCode: true, SkipCode: true,
SkipStorage: true, SkipStorage: true,
OnlyWithAddresses: false, OnlyWithAddresses: false,
@ -47,12 +48,12 @@ func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, st
if len(result.Accounts) != expectedNum { if len(result.Accounts) != expectedNum {
t.Fatalf("expected %d results, got %d", expectedNum, len(result.Accounts)) t.Fatalf("expected %d results, got %d", expectedNum, len(result.Accounts))
} }
for address := range result.Accounts { for addr, acc := range result.Accounts {
if address == (common.Address{}) { if strings.HasSuffix(addr, "pre") || acc.Address == nil {
t.Fatalf("empty address returned") t.Fatalf("account without prestate (address) returned: %v", addr)
} }
if !statedb.Exist(address) { if !statedb.Exist(*acc.Address) {
t.Fatalf("account not found in state %s", address.Hex()) t.Fatalf("account not found in state %s", acc.Address.Hex())
} }
} }
return result return result
@ -92,16 +93,16 @@ func TestAccountRange(t *testing.T) {
secondResult := accountRangeTest(t, &trie, sdb, common.BytesToHash(firstResult.Next), AccountRangeMaxResults, AccountRangeMaxResults) secondResult := accountRangeTest(t, &trie, sdb, common.BytesToHash(firstResult.Next), AccountRangeMaxResults, AccountRangeMaxResults)
hList := make([]common.Hash, 0) hList := make([]common.Hash, 0)
for addr1 := range firstResult.Accounts { for addr1, acc := range firstResult.Accounts {
// If address is empty, then it makes no sense to compare // If address is non-available, then it makes no sense to compare
// them as they might be two different accounts. // them as they might be two different accounts.
if addr1 == (common.Address{}) { if acc.Address == nil {
continue continue
} }
if _, duplicate := secondResult.Accounts[addr1]; duplicate { if _, duplicate := secondResult.Accounts[addr1]; duplicate {
t.Fatalf("pagination test failed: results should not overlap") t.Fatalf("pagination test failed: results should not overlap")
} }
hList = append(hList, crypto.Keccak256Hash(addr1.Bytes())) hList = append(hList, crypto.Keccak256Hash(acc.Address.Bytes()))
} }
// Test to see if it's possible to recover from the middle of the previous // Test to see if it's possible to recover from the middle of the previous
// set and get an even split between the first and second sets. // set and get an even split between the first and second sets.
@ -140,7 +141,7 @@ func TestEmptyAccountRange(t *testing.T) {
st.Commit(0, true) st.Commit(0, true)
st, _ = state.New(types.EmptyRootHash, statedb, nil) st, _ = state.New(types.EmptyRootHash, statedb, nil)
results := st.IteratorDump(&state.DumpConfig{ results := st.RawDump(&state.DumpConfig{
SkipCode: true, SkipCode: true,
SkipStorage: true, SkipStorage: true,
OnlyWithAddresses: true, OnlyWithAddresses: true,

View file

@ -611,7 +611,8 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (engine.PayloadS
// Although we don't want to trigger a sync, if there is one already in // Although we don't want to trigger a sync, if there is one already in
// progress, try to extend if with the current payload request to relieve // progress, try to extend if with the current payload request to relieve
// some strain from the forkchoice update. // some strain from the forkchoice update.
if err := api.eth.Downloader().BeaconExtend(api.eth.SyncMode(), block.Header()); err == nil { err := api.eth.Downloader().BeaconExtend(api.eth.SyncMode(), block.Header())
if err == nil {
log.Debug("Payload accepted for sync extension", "number", block.NumberU64(), "hash", block.Hash()) log.Debug("Payload accepted for sync extension", "number", block.NumberU64(), "hash", block.Hash())
return engine.PayloadStatusV1{Status: engine.SYNCING}, nil return engine.PayloadStatusV1{Status: engine.SYNCING}, nil
} }
@ -623,12 +624,12 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) (engine.PayloadS
// In full sync mode, failure to import a well-formed block can only mean // In full sync mode, failure to import a well-formed block can only mean
// that the parent state is missing and the syncer rejected extending the // that the parent state is missing and the syncer rejected extending the
// current cycle with the new payload. // current cycle with the new payload.
log.Warn("Ignoring payload with missing parent", "number", block.NumberU64(), "hash", block.Hash(), "parent", block.ParentHash()) log.Warn("Ignoring payload with missing parent", "number", block.NumberU64(), "hash", block.Hash(), "parent", block.ParentHash(), "reason", err)
} else { } else {
// In non-full sync mode (i.e. snap sync) all payloads are rejected until // In non-full sync mode (i.e. snap sync) all payloads are rejected until
// snap sync terminates as snap sync relies on direct database injections // snap sync terminates as snap sync relies on direct database injections
// and cannot afford concurrent out-if-band modifications via imports. // and cannot afford concurrent out-if-band modifications via imports.
log.Warn("Ignoring payload while snap syncing", "number", block.NumberU64(), "hash", block.Hash()) log.Warn("Ignoring payload while snap syncing", "number", block.NumberU64(), "hash", block.Hash(), "reason", err)
} }
return engine.PayloadStatusV1{Status: engine.SYNCING}, nil return engine.PayloadStatusV1{Status: engine.SYNCING}, nil
} }

View file

@ -1562,7 +1562,7 @@ func TestBlockToPayloadWithBlobs(t *testing.T) {
// This checks that beaconRoot is applied to the state from the engine API. // This checks that beaconRoot is applied to the state from the engine API.
func TestParentBeaconBlockRoot(t *testing.T) { func TestParentBeaconBlockRoot(t *testing.T) {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(colorable.NewColorableStderr(), log.LevelTrace, true)))
genesis, blocks := generateMergeChain(10, true) genesis, blocks := generateMergeChain(10, true)

View file

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"math/rand" "math/rand"
"os"
"sync" "sync"
"testing" "testing"
"time" "time"
@ -31,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"golang.org/x/exp/slog"
) )
// makeChain creates a chain of n blocks starting at and including parent. // makeChain creates a chain of n blocks starting at and including parent.
@ -271,7 +273,7 @@ func XTestDelivery(t *testing.T) {
world.chain = blo world.chain = blo
world.progress(10) world.progress(10)
if false { if false {
log.Root().SetHandler(log.StdoutHandler) log.SetDefault(log.NewLogger(slog.NewTextHandler(os.Stdout, nil)))
} }
q := newQueue(10, 10) q := newQueue(10, 10)
var wg sync.WaitGroup var wg sync.WaitGroup

View file

@ -69,9 +69,17 @@ var errSyncReorged = errors.New("sync reorged")
// might still be propagating. // might still be propagating.
var errTerminated = errors.New("terminated") var errTerminated = errors.New("terminated")
// errReorgDenied is returned if an attempt is made to extend the beacon chain // errChainReorged is an internal helper error to signal that the header chain
// with a new header, but it does not link up to the existing sync. // of the current sync cycle was (partially) reorged.
var errReorgDenied = errors.New("non-forced head reorg denied") var errChainReorged = errors.New("chain reorged")
// errChainGapped is an internal helper error to signal that the header chain
// of the current sync cycle is gaped with the one advertised by consensus client.
var errChainGapped = errors.New("chain gapped")
// errChainForked is an internal helper error to signal that the header chain
// of the current sync cycle is forked with the one advertised by consensus client.
var errChainForked = errors.New("chain forked")
func init() { func init() {
// Tuning parameters is nice, but the scratch space must be assignable in // Tuning parameters is nice, but the scratch space must be assignable in
@ -271,9 +279,9 @@ func (s *skeleton) startup() {
newhead, err := s.sync(head) newhead, err := s.sync(head)
switch { switch {
case err == errSyncLinked: case err == errSyncLinked:
// Sync cycle linked up to the genesis block. Tear down the loop // Sync cycle linked up to the genesis block, or the existent chain
// and restart it so, it can properly notify the backfiller. Don't // segment. Tear down the loop and restart it so, it can properly
// account a new head. // notify the backfiller. Don't account a new head.
head = nil head = nil
case err == errSyncMerged: case err == errSyncMerged:
@ -457,15 +465,16 @@ func (s *skeleton) sync(head *types.Header) (*types.Header, error) {
// we don't seamlessly integrate reorgs to keep things simple. If the // we don't seamlessly integrate reorgs to keep things simple. If the
// network starts doing many mini reorgs, it might be worthwhile handling // network starts doing many mini reorgs, it might be worthwhile handling
// a limited depth without an error. // a limited depth without an error.
if reorged := s.processNewHead(event.header, event.final, event.force); reorged { if err := s.processNewHead(event.header, event.final); err != nil {
// If a reorg is needed, and we're forcing the new head, signal // If a reorg is needed, and we're forcing the new head, signal
// the syncer to tear down and start over. Otherwise, drop the // the syncer to tear down and start over. Otherwise, drop the
// non-force reorg. // non-force reorg.
if event.force { if event.force {
event.errc <- nil // forced head reorg accepted event.errc <- nil // forced head reorg accepted
log.Info("Restarting sync cycle", "reason", err)
return event.header, errSyncReorged return event.header, errSyncReorged
} }
event.errc <- errReorgDenied event.errc <- err
continue continue
} }
event.errc <- nil // head extension accepted event.errc <- nil // head extension accepted
@ -610,7 +619,7 @@ func (s *skeleton) saveSyncStatus(db ethdb.KeyValueWriter) {
// accepts and integrates it into the skeleton or requests a reorg. Upon reorg, // accepts and integrates it into the skeleton or requests a reorg. Upon reorg,
// the syncer will tear itself down and restart with a fresh head. It is simpler // the syncer will tear itself down and restart with a fresh head. It is simpler
// to reconstruct the sync state than to mutate it and hope for the best. // to reconstruct the sync state than to mutate it and hope for the best.
func (s *skeleton) processNewHead(head *types.Header, final *types.Header, force bool) bool { func (s *skeleton) processNewHead(head *types.Header, final *types.Header) error {
// If a new finalized block was announced, update the sync process independent // If a new finalized block was announced, update the sync process independent
// of what happens with the sync head below // of what happens with the sync head below
if final != nil { if final != nil {
@ -631,26 +640,17 @@ func (s *skeleton) processNewHead(head *types.Header, final *types.Header, force
// once more, ignore it instead of tearing down sync for a noop. // once more, ignore it instead of tearing down sync for a noop.
if lastchain.Head == lastchain.Tail { if lastchain.Head == lastchain.Tail {
if current := rawdb.ReadSkeletonHeader(s.db, number); current.Hash() == head.Hash() { if current := rawdb.ReadSkeletonHeader(s.db, number); current.Hash() == head.Hash() {
return false return nil
} }
} }
// Not a noop / double head announce, abort with a reorg // Not a noop / double head announce, abort with a reorg
if force { return fmt.Errorf("%w, tail: %d, head: %d, newHead: %d", errChainReorged, lastchain.Tail, lastchain.Head, number)
log.Warn("Beacon chain reorged", "tail", lastchain.Tail, "head", lastchain.Head, "newHead", number)
}
return true
} }
if lastchain.Head+1 < number { if lastchain.Head+1 < number {
if force { return fmt.Errorf("%w, head: %d, newHead: %d", errChainGapped, lastchain.Head, number)
log.Warn("Beacon chain gapped", "head", lastchain.Head, "newHead", number)
}
return true
} }
if parent := rawdb.ReadSkeletonHeader(s.db, number-1); parent.Hash() != head.ParentHash { if parent := rawdb.ReadSkeletonHeader(s.db, number-1); parent.Hash() != head.ParentHash {
if force { return fmt.Errorf("%w, ancestor: %d, hash: %s, want: %s", errChainForked, number-1, parent.Hash(), head.ParentHash)
log.Warn("Beacon chain forked", "ancestor", number-1, "hash", parent.Hash(), "want", head.ParentHash)
}
return true
} }
// New header seems to be in the last subchain range. Unwind any extra headers // New header seems to be in the last subchain range. Unwind any extra headers
// from the chain tip and insert the new head. We won't delete any trimmed // from the chain tip and insert the new head. We won't delete any trimmed
@ -666,7 +666,7 @@ func (s *skeleton) processNewHead(head *types.Header, final *types.Header, force
if err := batch.Write(); err != nil { if err := batch.Write(); err != nil {
log.Crit("Failed to write skeleton sync status", "err", err) log.Crit("Failed to write skeleton sync status", "err", err)
} }
return false return nil
} }
// assignTasks attempts to match idle peers to pending header retrievals. // assignTasks attempts to match idle peers to pending header retrievals.

View file

@ -434,7 +434,7 @@ func TestSkeletonSyncExtend(t *testing.T) {
newstate: []*subchain{ newstate: []*subchain{
{Head: 49, Tail: 49}, {Head: 49, Tail: 49},
}, },
err: errReorgDenied, err: errChainReorged,
}, },
// Initialize a sync and try to extend it with a number-wise sequential // Initialize a sync and try to extend it with a number-wise sequential
// header, but a hash wise non-linking one. // header, but a hash wise non-linking one.
@ -444,7 +444,7 @@ func TestSkeletonSyncExtend(t *testing.T) {
newstate: []*subchain{ newstate: []*subchain{
{Head: 49, Tail: 49}, {Head: 49, Tail: 49},
}, },
err: errReorgDenied, err: errChainForked,
}, },
// Initialize a sync and try to extend it with a non-linking future block. // Initialize a sync and try to extend it with a non-linking future block.
{ {
@ -453,7 +453,7 @@ func TestSkeletonSyncExtend(t *testing.T) {
newstate: []*subchain{ newstate: []*subchain{
{Head: 49, Tail: 49}, {Head: 49, Tail: 49},
}, },
err: errReorgDenied, err: errChainGapped,
}, },
// Initialize a sync and try to extend it with a past canonical block. // Initialize a sync and try to extend it with a past canonical block.
{ {
@ -462,7 +462,7 @@ func TestSkeletonSyncExtend(t *testing.T) {
newstate: []*subchain{ newstate: []*subchain{
{Head: 50, Tail: 50}, {Head: 50, Tail: 50},
}, },
err: errReorgDenied, err: errChainReorged,
}, },
// Initialize a sync and try to extend it with a past sidechain block. // Initialize a sync and try to extend it with a past sidechain block.
{ {
@ -471,7 +471,7 @@ func TestSkeletonSyncExtend(t *testing.T) {
newstate: []*subchain{ newstate: []*subchain{
{Head: 50, Tail: 50}, {Head: 50, Tail: 50},
}, },
err: errReorgDenied, err: errChainReorged,
}, },
} }
for i, tt := range tests { for i, tt := range tests {
@ -487,7 +487,7 @@ func TestSkeletonSyncExtend(t *testing.T) {
skeleton.Sync(tt.head, nil, true) skeleton.Sync(tt.head, nil, true)
<-wait <-wait
if err := skeleton.Sync(tt.extend, nil, false); err != tt.err { if err := skeleton.Sync(tt.extend, nil, false); !errors.Is(err, tt.err) {
t.Errorf("test %d: extension failure mismatch: have %v, want %v", i, err, tt.err) t.Errorf("test %d: extension failure mismatch: have %v, want %v", i, err, tt.err)
} }
skeleton.Terminate() skeleton.Terminate()

View file

@ -483,7 +483,7 @@ func (f *BlockFetcher) loop() {
select { select {
case res := <-resCh: case res := <-resCh:
res.Done <- nil res.Done <- nil
f.FilterHeaders(peer, *res.Res.(*eth.BlockHeadersRequest), time.Now().Add(res.Time)) f.FilterHeaders(peer, *res.Res.(*eth.BlockHeadersRequest), time.Now())
case <-timeout.C: case <-timeout.C:
// The peer didn't respond in time. The request // The peer didn't respond in time. The request

View file

@ -180,7 +180,7 @@ func TestFilters(t *testing.T) {
// Hack: GenerateChainWithGenesis creates a new db. // Hack: GenerateChainWithGenesis creates a new db.
// Commit the genesis manually and use GenerateChain. // Commit the genesis manually and use GenerateChain.
_, err = gspec.Commit(db, trie.NewDatabase(db, nil), nil) _, err = gspec.Commit(db, trie.NewDatabase(db, nil))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -0,0 +1,235 @@
// 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 gasestimator
import (
"context"
"errors"
"fmt"
"math"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"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/log"
"github.com/ethereum/go-ethereum/params"
)
// Options are the contextual parameters to execute the requested call.
//
// Whilst it would be possible to pass a blockchain object that aggregates all
// these together, it would be excessively hard to test. Splitting the parts out
// allows testing without needing a proper live chain.
type Options struct {
Config *params.ChainConfig // Chain configuration for hard fork selection
Chain core.ChainContext // Chain context to access past block hashes
Header *types.Header // Header defining the block context to execute in
State *state.StateDB // Pre-state on top of which to estimate the gas
ErrorRatio float64 // Allowed overestimation ratio for faster estimation termination
}
// Estimate returns the lowest possible gas limit that allows the transaction to
// run successfully with the provided context optons. It returns an error if the
// transaction would always revert, or if there are unexpected failures.
func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uint64) (uint64, []byte, error) {
// Binary search the gas limit, as it may need to be higher than the amount used
var (
lo uint64 // lowest-known gas limit where tx execution fails
hi uint64 // lowest-known gas limit where tx execution succeeds
)
// Determine the highest gas limit can be used during the estimation.
hi = opts.Header.GasLimit
if call.GasLimit >= params.TxGas {
hi = call.GasLimit
}
// Normalize the max fee per gas the call is willing to spend.
var feeCap *big.Int
if call.GasFeeCap != nil {
feeCap = call.GasFeeCap
} else if call.GasPrice != nil {
feeCap = call.GasPrice
} else {
feeCap = common.Big0
}
// Recap the highest gas limit with account's available balance.
if feeCap.BitLen() != 0 {
balance := opts.State.GetBalance(call.From)
available := new(big.Int).Set(balance)
if call.Value != nil {
if call.Value.Cmp(available) >= 0 {
return 0, nil, core.ErrInsufficientFundsForTransfer
}
available.Sub(available, call.Value)
}
allowance := new(big.Int).Div(available, feeCap)
// If the allowance is larger than maximum uint64, skip checking
if allowance.IsUint64() && hi > allowance.Uint64() {
transfer := call.Value
if transfer == nil {
transfer = new(big.Int)
}
log.Debug("Gas estimation capped by limited funds", "original", hi, "balance", balance,
"sent", transfer, "maxFeePerGas", feeCap, "fundable", allowance)
hi = allowance.Uint64()
}
}
// Recap the highest gas allowance with specified gascap.
if gasCap != 0 && hi > gasCap {
log.Debug("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
hi = gasCap
}
// If the transaction is a plain value transfer, short circuit estimation and
// directly try 21000. Returning 21000 without any execution is dangerous as
// some tx field combos might bump the price up even for plain transfers (e.g.
// unused access list items). Ever so slightly wasteful, but safer overall.
if len(call.Data) == 0 {
if call.To != nil && opts.State.GetCodeSize(*call.To) == 0 {
failed, _, err := execute(ctx, call, opts, params.TxGas)
if !failed && err == nil {
return params.TxGas, nil, nil
}
}
}
// We first execute the transaction at the highest allowable gas limit, since if this fails we
// can return error immediately.
failed, result, err := execute(ctx, call, opts, hi)
if err != nil {
return 0, nil, err
}
if failed {
if result != nil && !errors.Is(result.Err, vm.ErrOutOfGas) {
return 0, result.Revert(), result.Err
}
return 0, nil, fmt.Errorf("gas required exceeds allowance (%d)", hi)
}
// For almost any transaction, the gas consumed by the unconstrained execution
// above lower-bounds the gas limit required for it to succeed. One exception
// is those that explicitly check gas remaining in order to execute within a
// given limit, but we probably don't want to return the lowest possible gas
// limit for these cases anyway.
lo = result.UsedGas - 1
// There's a fairly high chance for the transaction to execute successfully
// with gasLimit set to the first execution's usedGas + gasRefund. Explicitly
// check that gas amount and use as a limit for the binary search.
optimisticGasLimit := (result.UsedGas + result.RefundedGas + params.CallStipend) * 64 / 63
if optimisticGasLimit < hi {
failed, _, err = execute(ctx, call, opts, optimisticGasLimit)
if err != nil {
// This should not happen under normal conditions since if we make it this far the
// transaction had run without error at least once before.
log.Error("Execution error in estimate gas", "err", err)
return 0, nil, err
}
if failed {
lo = optimisticGasLimit
} else {
hi = optimisticGasLimit
}
}
// Binary search for the smallest gas limit that allows the tx to execute successfully.
for lo+1 < hi {
if opts.ErrorRatio > 0 {
// It is a bit pointless to return a perfect estimation, as changing
// network conditions require the caller to bump it up anyway. Since
// wallets tend to use 20-25% bump, allowing a small approximation
// error is fine (as long as it's upwards).
if float64(hi-lo)/float64(hi) < opts.ErrorRatio {
break
}
}
mid := (hi + lo) / 2
if mid > lo*2 {
// Most txs don't need much higher gas limit than their gas used, and most txs don't
// require near the full block limit of gas, so the selection of where to bisect the
// range here is skewed to favor the low side.
mid = lo * 2
}
failed, _, err = execute(ctx, call, opts, mid)
if err != nil {
// This should not happen under normal conditions since if we make it this far the
// transaction had run without error at least once before.
log.Error("Execution error in estimate gas", "err", err)
return 0, nil, err
}
if failed {
lo = mid
} else {
hi = mid
}
}
return hi, nil, nil
}
// execute is a helper that executes the transaction under a given gas limit and
// returns true if the transaction fails for a reason that might be related to
// not enough gas. A non-nil error means execution failed due to reasons unrelated
// to the gas limit.
func execute(ctx context.Context, call *core.Message, opts *Options, gasLimit uint64) (bool, *core.ExecutionResult, error) {
// Configure the call for this specific execution (and revert the change after)
defer func(gas uint64) { call.GasLimit = gas }(call.GasLimit)
call.GasLimit = gasLimit
// Execute the call and separate execution faults caused by a lack of gas or
// other non-fixable conditions
result, err := run(ctx, call, opts)
if err != nil {
if errors.Is(err, core.ErrIntrinsicGas) {
return true, nil, nil // Special case, raise gas limit
}
return true, nil, err // Bail out
}
return result.Failed(), result, nil
}
// run assembles the EVM as defined by the consensus rules and runs the requested
// call invocation.
func run(ctx context.Context, call *core.Message, opts *Options) (*core.ExecutionResult, error) {
// Assemble the call and the call context
var (
msgContext = core.NewEVMTxContext(call)
evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil)
dirtyState = opts.State.Copy()
evm = vm.NewEVM(evmContext, msgContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true})
)
// Monitor the outer context and interrupt the EVM upon cancellation. To avoid
// a dangling goroutine until the outer estimation finishes, create an internal
// context for the lifetime of this method call.
ctx, cancel := context.WithCancel(ctx)
defer cancel()
go func() {
<-ctx.Done()
evm.Cancel()
}()
// Execute the call, returning a wrapped error or the result
result, err := core.ApplyMessage(evm, call, new(core.GasPool).AddGas(math.MaxUint64))
if vmerr := dirtyState.Error(); vmerr != nil {
return nil, vmerr
}
if err != nil {
return result, fmt.Errorf("failed with %d gas: %w", call.GasLimit, err)
}
return result, nil
}

View file

@ -166,6 +166,7 @@ type TraceCallConfig struct {
TraceConfig TraceConfig
StateOverrides *ethapi.StateOverride StateOverrides *ethapi.StateOverride
BlockOverrides *ethapi.BlockOverrides BlockOverrides *ethapi.BlockOverrides
TxIndex *hexutil.Uint
} }
// StdTraceConfig holds extra parameters to standard-json trace functions. // StdTraceConfig holds extra parameters to standard-json trace functions.
@ -865,11 +866,17 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
// TraceCall lets you trace a given eth_call. It collects the structured logs // TraceCall lets you trace a given eth_call. It collects the structured logs
// created during the execution of EVM if the given transaction was added on // created during the execution of EVM if the given transaction was added on
// top of the provided block and returns them as a JSON object. // top of the provided block and returns them as a JSON object.
// If no transaction index is specified, the trace will be conducted on the state
// after executing the specified block. However, if a transaction index is provided,
// the trace will be conducted on the state after executing the specified transaction
// within the specified block.
func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) { func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
// Try to retrieve the specified block // Try to retrieve the specified block
var ( var (
err error err error
block *types.Block block *types.Block
statedb *state.StateDB
release StateReleaseFunc
) )
if hash, ok := blockNrOrHash.Hash(); ok { if hash, ok := blockNrOrHash.Hash(); ok {
block, err = api.blockByHash(ctx, hash) block, err = api.blockByHash(ctx, hash)
@ -894,7 +901,12 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
if config != nil && config.Reexec != nil { if config != nil && config.Reexec != nil {
reexec = *config.Reexec reexec = *config.Reexec
} }
statedb, release, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
if config != nil && config.TxIndex != nil {
_, _, statedb, release, err = api.backend.StateAtTransaction(ctx, block, int(*config.TxIndex), reexec)
} else {
statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -200,13 +200,51 @@ func TestTraceCall(t *testing.T) {
} }
genBlocks := 10 genBlocks := 10
signer := types.HomesteadSigner{} signer := types.HomesteadSigner{}
nonce := uint64(0)
backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
// Transfer from account[0] to account[1] // Transfer from account[0] to account[1]
// value: 1000 wei // value: 1000 wei
// fee: 0 wei // fee: 0 wei
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
Nonce: nonce,
To: &accounts[1].addr,
Value: big.NewInt(1000),
Gas: params.TxGas,
GasPrice: b.BaseFee(),
Data: nil}),
signer, accounts[0].key)
b.AddTx(tx) b.AddTx(tx)
nonce++
if i == genBlocks-2 {
// Transfer from account[0] to account[2]
tx, _ = types.SignTx(types.NewTx(&types.LegacyTx{
Nonce: nonce,
To: &accounts[2].addr,
Value: big.NewInt(1000),
Gas: params.TxGas,
GasPrice: b.BaseFee(),
Data: nil}),
signer, accounts[0].key)
b.AddTx(tx)
nonce++
// Transfer from account[0] to account[1] again
tx, _ = types.SignTx(types.NewTx(&types.LegacyTx{
Nonce: nonce,
To: &accounts[1].addr,
Value: big.NewInt(1000),
Gas: params.TxGas,
GasPrice: b.BaseFee(),
Data: nil}),
signer, accounts[0].key)
b.AddTx(tx)
nonce++
}
}) })
uintPtr := func(i int) *hexutil.Uint { x := hexutil.Uint(i); return &x }
defer backend.teardown() defer backend.teardown()
api := NewAPI(backend) api := NewAPI(backend)
var testSuite = []struct { var testSuite = []struct {
@ -240,6 +278,51 @@ func TestTraceCall(t *testing.T) {
expectErr: nil, expectErr: nil,
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`, expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
}, },
// Upon the last state, default to the post block's state
{
blockNumber: rpc.BlockNumber(genBlocks - 1),
call: ethapi.TransactionArgs{
From: &accounts[2].addr,
To: &accounts[0].addr,
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
},
config: nil,
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
},
// Before the first transaction, should be failed
{
blockNumber: rpc.BlockNumber(genBlocks - 1),
call: ethapi.TransactionArgs{
From: &accounts[2].addr,
To: &accounts[0].addr,
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
},
config: &TraceCallConfig{TxIndex: uintPtr(0)},
expectErr: fmt.Errorf("tracing failed: insufficient funds for gas * price + value: address %s have 1000000000000000000 want 1000000000000000100", accounts[2].addr),
},
// Before the target transaction, should be failed
{
blockNumber: rpc.BlockNumber(genBlocks - 1),
call: ethapi.TransactionArgs{
From: &accounts[2].addr,
To: &accounts[0].addr,
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
},
config: &TraceCallConfig{TxIndex: uintPtr(1)},
expectErr: fmt.Errorf("tracing failed: insufficient funds for gas * price + value: address %s have 1000000000000000000 want 1000000000000000100", accounts[2].addr),
},
// After the target transaction, should be succeed
{
blockNumber: rpc.BlockNumber(genBlocks - 1),
call: ethapi.TransactionArgs{
From: &accounts[2].addr,
To: &accounts[0].addr,
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
},
config: &TraceCallConfig{TxIndex: uintPtr(2)},
expectErr: nil,
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
},
// Standard JSON trace upon the non-existent block, error expects // Standard JSON trace upon the non-existent block, error expects
{ {
blockNumber: rpc.BlockNumber(genBlocks + 1), blockNumber: rpc.BlockNumber(genBlocks + 1),
@ -297,8 +380,8 @@ func TestTraceCall(t *testing.T) {
t.Errorf("test %d: expect error %v, got nothing", i, testspec.expectErr) t.Errorf("test %d: expect error %v, got nothing", i, testspec.expectErr)
continue continue
} }
if !reflect.DeepEqual(err, testspec.expectErr) { if !reflect.DeepEqual(err.Error(), testspec.expectErr.Error()) {
t.Errorf("test %d: error mismatch, want %v, git %v", i, testspec.expectErr, err) t.Errorf("test %d: error mismatch, want '%v', got '%v'", i, testspec.expectErr, err)
} }
} else { } else {
if err != nil { if err != nil {
@ -338,7 +421,14 @@ func TestTraceTransaction(t *testing.T) {
// Transfer from account[0] to account[1] // Transfer from account[0] to account[1]
// value: 1000 wei // value: 1000 wei
// fee: 0 wei // fee: 0 wei
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
Nonce: uint64(i),
To: &accounts[1].addr,
Value: big.NewInt(1000),
Gas: params.TxGas,
GasPrice: b.BaseFee(),
Data: nil}),
signer, accounts[0].key)
b.AddTx(tx) b.AddTx(tx)
target = tx.Hash() target = tx.Hash()
}) })
@ -388,7 +478,14 @@ func TestTraceBlock(t *testing.T) {
// Transfer from account[0] to account[1] // Transfer from account[0] to account[1]
// value: 1000 wei // value: 1000 wei
// fee: 0 wei // fee: 0 wei
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
Nonce: uint64(i),
To: &accounts[1].addr,
Value: big.NewInt(1000),
Gas: params.TxGas,
GasPrice: b.BaseFee(),
Data: nil}),
signer, accounts[0].key)
b.AddTx(tx) b.AddTx(tx)
txHash = tx.Hash() txHash = tx.Hash()
}) })
@ -478,7 +575,14 @@ func TestTracingWithOverrides(t *testing.T) {
// Transfer from account[0] to account[1] // Transfer from account[0] to account[1]
// value: 1000 wei // value: 1000 wei
// fee: 0 wei // fee: 0 wei
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key) tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
Nonce: uint64(i),
To: &accounts[1].addr,
Value: big.NewInt(1000),
Gas: params.TxGas,
GasPrice: b.BaseFee(),
Data: nil}),
signer, accounts[0].key)
b.AddTx(tx) b.AddTx(tx)
}) })
defer backend.chain.Stop() defer backend.chain.Stop()

View file

@ -119,7 +119,7 @@ func (f *Firehose) resetTransaction() {
f.deferredCallState.Reset() f.deferredCallState.Reset()
} }
func (f *Firehose) OnBlockStart(b *types.Block, td *big.Int, finalized *types.Header, safe *types.Header) { func (f *Firehose) OnBlockStart(b *types.Block, td *big.Int, finalized *types.Header, safe *types.Header, chainConfig *params.ChainConfig) {
firehoseDebug("block start number=%d hash=%s", b.NumberU64(), b.Hash()) firehoseDebug("block start number=%d hash=%s", b.NumberU64(), b.Hash())
f.ensureNotInBlock() f.ensureNotInBlock()
@ -427,7 +427,7 @@ func (f *Firehose) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad
f.callStack.Peek().Suicide = true f.callStack.Peek().Suicide = true
if value.Sign() != 0 { if value.Sign() != 0 {
f.OnBalanceChange(from, value, common.Big0, state.BalanceChangeSuicideWithdraw) f.OnBalanceChange(from, value, common.Big0, state.BalanceDecreaseSelfdestruct)
} }
// The next CaptureExit must be ignored, this variable will make the next CaptureExit to be ignored // The next CaptureExit must be ignored, this variable will make the next CaptureExit to be ignored
@ -619,7 +619,7 @@ func (f *Firehose) CaptureKeccakPreimage(hash common.Hash, data []byte) {
} }
func (f *Firehose) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) { func (f *Firehose) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) {
f.OnBlockStart(b, big.NewInt(0), nil, nil) f.OnBlockStart(b, big.NewInt(0), nil, nil, nil)
f.captureTxStart(types.NewTx(&types.LegacyTx{}), emptyCommonHash, emptyCommonAddress, emptyCommonAddress, func(common.Address) bool { return false }, false) f.captureTxStart(types.NewTx(&types.LegacyTx{}), emptyCommonHash, emptyCommonAddress, emptyCommonAddress, func(common.Address) bool { return false }, false)
f.CaptureStart(emptyCommonAddress, emptyCommonAddress, false, nil, 0, nil) f.CaptureStart(emptyCommonAddress, emptyCommonAddress, false, nil, 0, nil)
@ -1174,20 +1174,20 @@ func newAccessListFromChain(accessList types.AccessList) (out []*pbeth.AccessTup
} }
var balanceChangeReasonToPb = map[state.BalanceChangeReason]pbeth.BalanceChange_Reason{ var balanceChangeReasonToPb = map[state.BalanceChangeReason]pbeth.BalanceChange_Reason{
state.BalanceChangeRewardMineUncle: pbeth.BalanceChange_REASON_REWARD_MINE_UNCLE, state.BalanceIncreaseRewardMineUncle: pbeth.BalanceChange_REASON_REWARD_MINE_UNCLE,
state.BalanceChangeRewardMineBlock: pbeth.BalanceChange_REASON_REWARD_MINE_BLOCK, state.BalanceIncreaseRewardMineBlock: pbeth.BalanceChange_REASON_REWARD_MINE_BLOCK,
state.BalanceChangeDaoRefundContract: pbeth.BalanceChange_REASON_DAO_REFUND_CONTRACT, state.BalanceIncreaseDaoContract: pbeth.BalanceChange_REASON_DAO_REFUND_CONTRACT,
state.BalanceChangeDaoAdjustBalance: pbeth.BalanceChange_REASON_DAO_ADJUST_BALANCE, state.BalanceDecreaseDaoAccount: pbeth.BalanceChange_REASON_DAO_ADJUST_BALANCE,
state.BalanceChangeTransfer: pbeth.BalanceChange_REASON_TRANSFER, state.BalanceChangeTransfer: pbeth.BalanceChange_REASON_TRANSFER,
state.BalanceChangeGenesisBalance: pbeth.BalanceChange_REASON_GENESIS_BALANCE, state.BalanceIncreaseGenesisBalance: pbeth.BalanceChange_REASON_GENESIS_BALANCE,
state.BalanceChangeGasBuy: pbeth.BalanceChange_REASON_GAS_BUY, state.BalanceDecreaseGasBuy: pbeth.BalanceChange_REASON_GAS_BUY,
state.BalanceChangeRewardTransactionFee: pbeth.BalanceChange_REASON_REWARD_TRANSACTION_FEE, state.BalanceIncreaseRewardTransactionFee: pbeth.BalanceChange_REASON_REWARD_TRANSACTION_FEE,
state.BalanceChangeGasRefund: pbeth.BalanceChange_REASON_GAS_REFUND, state.BalanceIncreaseGasReturn: pbeth.BalanceChange_REASON_GAS_REFUND,
state.BalanceChangeTouchAccount: pbeth.BalanceChange_REASON_TOUCH_ACCOUNT, state.BalanceChangeTouchAccount: pbeth.BalanceChange_REASON_TOUCH_ACCOUNT,
state.BalanceChangeSuicideRefund: pbeth.BalanceChange_REASON_SUICIDE_REFUND, state.BalanceIncreaseSelfdestruct: pbeth.BalanceChange_REASON_SUICIDE_REFUND,
state.BalanceChangeSuicideWithdraw: pbeth.BalanceChange_REASON_SUICIDE_WITHDRAW, state.BalanceDecreaseSelfdestruct: pbeth.BalanceChange_REASON_SUICIDE_WITHDRAW,
state.BalanceChangeBurn: pbeth.BalanceChange_REASON_BURN, state.BalanceDecreaseSelfdestructBurn: pbeth.BalanceChange_REASON_BURN,
state.BalanceChangeWithdrawal: pbeth.BalanceChange_REASON_WITHDRAWAL, state.BalanceChangeWithdrawal: pbeth.BalanceChange_REASON_WITHDRAWAL,
state.BalanceChangeUnspecified: pbeth.BalanceChange_REASON_UNKNOWN, state.BalanceChangeUnspecified: pbeth.BalanceChange_REASON_UNKNOWN,
} }

View file

@ -118,7 +118,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
} }
statedb.SetLogger(tracer) statedb.SetLogger(tracer)
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer}) evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
msg, err := core.TransactionToMessage(tx, signer, nil) msg, err := core.TransactionToMessage(tx, signer, test.Genesis.BaseFee)
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)
} }

View file

@ -83,7 +83,7 @@
}, },
"post": { "post": {
"0x808b4da0be6c9512e948521452227efc619bea52": { "0x808b4da0be6c9512e948521452227efc619bea52": {
"balance": "0x2cd72a36dd031f089", "balance": "0x2cd987071ba2346b6",
"nonce": 1223933 "nonce": 1223933
}, },
"0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": { "0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": {

View file

@ -144,19 +144,29 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (dire
vm: vm, vm: vm,
ctx: make(map[string]goja.Value), ctx: make(map[string]goja.Value),
} }
t.setTypeConverters()
t.setBuiltinFunctions()
if ctx == nil { if ctx == nil {
ctx = new(directory.Context) ctx = new(directory.Context)
} }
if ctx.BlockHash != (common.Hash{}) { if ctx.BlockHash != (common.Hash{}) {
t.ctx["blockHash"] = vm.ToValue(ctx.BlockHash.Bytes()) blockHash, err := t.toBuf(vm, ctx.BlockHash.Bytes())
if err != nil {
return nil, err
}
t.ctx["blockHash"] = blockHash
if ctx.TxHash != (common.Hash{}) { if ctx.TxHash != (common.Hash{}) {
t.ctx["txIndex"] = vm.ToValue(ctx.TxIndex) t.ctx["txIndex"] = vm.ToValue(ctx.TxIndex)
t.ctx["txHash"] = vm.ToValue(ctx.TxHash.Bytes()) txHash, err := t.toBuf(vm, ctx.TxHash.Bytes())
if err != nil {
return nil, err
}
t.ctx["txHash"] = txHash
} }
} }
t.setTypeConverters()
t.setBuiltinFunctions()
ret, err := vm.RunString("(" + code + ")") ret, err := vm.RunString("(" + code + ")")
if err != nil { if err != nil {
return nil, err return nil, err
@ -223,8 +233,14 @@ func (t *jsTracer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from commo
rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time) rules := env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time)
t.activePrecompiles = vm.ActivePrecompiles(rules) t.activePrecompiles = vm.ActivePrecompiles(rules)
t.ctx["block"] = t.vm.ToValue(t.env.Context.BlockNumber.Uint64()) t.ctx["block"] = t.vm.ToValue(t.env.Context.BlockNumber.Uint64())
t.ctx["gasPrice"] = t.vm.ToValue(t.env.TxContext.GasPrice)
t.ctx["gas"] = t.vm.ToValue(tx.Gas()) t.ctx["gas"] = t.vm.ToValue(tx.Gas())
gasPriceBig, err := t.toBig(t.vm, env.TxContext.GasPrice.String())
if err != nil {
t.err = err
t.env.Cancel()
return
}
t.ctx["gasPrice"] = gasPriceBig
} }
// CaptureTxEnd implements the Tracer interface and is invoked at the end of // CaptureTxEnd implements the Tracer interface and is invoked at the end of
@ -242,17 +258,36 @@ func (t *jsTracer) CaptureTxEnd(receipt *types.Receipt, err error) {
// CaptureStart implements the Tracer interface to initialize the tracing operation. // CaptureStart implements the Tracer interface to initialize the tracing operation.
func (t *jsTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { func (t *jsTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
cancel := func(err error) {
t.err = err
t.env.Cancel()
}
if create { if create {
t.ctx["type"] = t.vm.ToValue("CREATE") t.ctx["type"] = t.vm.ToValue("CREATE")
} else { } else {
t.ctx["type"] = t.vm.ToValue("CALL") t.ctx["type"] = t.vm.ToValue("CALL")
} }
t.ctx["from"] = t.vm.ToValue(from.Bytes()) fromVal, err := t.toBuf(t.vm, from.Bytes())
t.ctx["to"] = t.vm.ToValue(to.Bytes()) if err != nil {
t.ctx["input"] = t.vm.ToValue(input) cancel(err)
return
}
t.ctx["from"] = fromVal
toVal, err := t.toBuf(t.vm, to.Bytes())
if err != nil {
cancel(err)
return
}
t.ctx["to"] = toVal
inputVal, err := t.toBuf(t.vm, input)
if err != nil {
cancel(err)
return
}
t.ctx["input"] = inputVal
valueBig, err := t.toBig(t.vm, value.String()) valueBig, err := t.toBig(t.vm, value.String())
if err != nil { if err != nil {
t.err = err cancel(err)
return return
} }
t.ctx["value"] = valueBig t.ctx["value"] = valueBig
@ -297,10 +332,15 @@ func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope
// CaptureEnd is called after the call finishes to finalize the tracing. // CaptureEnd is called after the call finishes to finalize the tracing.
func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
t.ctx["output"] = t.vm.ToValue(output)
if err != nil { if err != nil {
t.ctx["error"] = t.vm.ToValue(err.Error()) t.ctx["error"] = t.vm.ToValue(err.Error())
} }
outputVal, err := t.toBuf(t.vm, output)
if err != nil {
t.err = err
return
}
t.ctx["output"] = outputVal
} }
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
@ -469,13 +509,13 @@ func (t *jsTracer) setBuiltinFunctions() {
} }
return false return false
}) })
vm.Set("slice", func(slice goja.Value, start, end int) goja.Value { vm.Set("slice", func(slice goja.Value, start, end int64) goja.Value {
b, err := t.fromBuf(vm, slice, false) b, err := t.fromBuf(vm, slice, false)
if err != nil { if err != nil {
vm.Interrupt(err) vm.Interrupt(err)
return nil return nil
} }
if start < 0 || start > end || end > len(b) { if start < 0 || start > end || end > int64(len(b)) {
vm.Interrupt(fmt.Sprintf("Tracer accessed out of bound memory: available %d, offset %d, size %d", len(b), start, end-start)) vm.Interrupt(fmt.Sprintf("Tracer accessed out of bound memory: available %d, offset %d, size %d", len(b), start, end-start))
return nil return nil
} }

View file

@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "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/eth/tracers/directory" "github.com/ethereum/go-ethereum/eth/tracers/directory"
"github.com/ethereum/go-ethereum/params"
) )
func init() { func init() {
@ -68,7 +69,6 @@ func (p *Printer) CaptureTxStart(env *vm.EVM, tx *types.Transaction, from common
return return
} }
fmt.Printf("CaptureTxStart: tx=%s\n", buf) fmt.Printf("CaptureTxStart: tx=%s\n", buf)
} }
func (p *Printer) CaptureTxEnd(receipt *types.Receipt, err error) { func (p *Printer) CaptureTxEnd(receipt *types.Receipt, err error) {
@ -84,7 +84,7 @@ func (p *Printer) CaptureTxEnd(receipt *types.Receipt, err error) {
fmt.Printf("CaptureTxEnd: receipt=%s\n", buf) fmt.Printf("CaptureTxEnd: receipt=%s\n", buf)
} }
func (p *Printer) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header) { func (p *Printer) OnBlockStart(b *types.Block, td *big.Int, finalized, safe *types.Header, _ *params.ChainConfig) {
if finalized != nil && safe != nil { if finalized != nil && safe != nil {
fmt.Printf("OnBlockStart: b=%v, td=%v, finalized=%v, safe=%v\n", b.NumberU64(), td, finalized.Number.Uint64(), safe.Number.Uint64()) fmt.Printf("OnBlockStart: b=%v, td=%v, finalized=%v, safe=%v\n", b.NumberU64(), td, finalized.Number.Uint64(), safe.Number.Uint64())
} else { } else {

View file

@ -23,7 +23,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) {
GasCost math.HexOrDecimal64 `json:"gasCost"` GasCost math.HexOrDecimal64 `json:"gasCost"`
Memory hexutil.Bytes `json:"memory,omitempty"` Memory hexutil.Bytes `json:"memory,omitempty"`
MemorySize int `json:"memSize"` MemorySize int `json:"memSize"`
Stack []uint256.Int `json:"stack"` Stack []hexutil.U256 `json:"stack"`
ReturnData hexutil.Bytes `json:"returnData,omitempty"` ReturnData hexutil.Bytes `json:"returnData,omitempty"`
Storage map[common.Hash]common.Hash `json:"-"` Storage map[common.Hash]common.Hash `json:"-"`
Depth int `json:"depth"` Depth int `json:"depth"`
@ -39,7 +39,12 @@ func (s StructLog) MarshalJSON() ([]byte, error) {
enc.GasCost = math.HexOrDecimal64(s.GasCost) enc.GasCost = math.HexOrDecimal64(s.GasCost)
enc.Memory = s.Memory enc.Memory = s.Memory
enc.MemorySize = s.MemorySize enc.MemorySize = s.MemorySize
enc.Stack = s.Stack if s.Stack != nil {
enc.Stack = make([]hexutil.U256, len(s.Stack))
for k, v := range s.Stack {
enc.Stack[k] = hexutil.U256(v)
}
}
enc.ReturnData = s.ReturnData enc.ReturnData = s.ReturnData
enc.Storage = s.Storage enc.Storage = s.Storage
enc.Depth = s.Depth enc.Depth = s.Depth
@ -59,7 +64,7 @@ func (s *StructLog) UnmarshalJSON(input []byte) error {
GasCost *math.HexOrDecimal64 `json:"gasCost"` GasCost *math.HexOrDecimal64 `json:"gasCost"`
Memory *hexutil.Bytes `json:"memory,omitempty"` Memory *hexutil.Bytes `json:"memory,omitempty"`
MemorySize *int `json:"memSize"` MemorySize *int `json:"memSize"`
Stack []uint256.Int `json:"stack"` Stack []hexutil.U256 `json:"stack"`
ReturnData *hexutil.Bytes `json:"returnData,omitempty"` ReturnData *hexutil.Bytes `json:"returnData,omitempty"`
Storage map[common.Hash]common.Hash `json:"-"` Storage map[common.Hash]common.Hash `json:"-"`
Depth *int `json:"depth"` Depth *int `json:"depth"`
@ -89,7 +94,10 @@ func (s *StructLog) UnmarshalJSON(input []byte) error {
s.MemorySize = *dec.MemorySize s.MemorySize = *dec.MemorySize
} }
if dec.Stack != nil { if dec.Stack != nil {
s.Stack = dec.Stack s.Stack = make([]uint256.Int, len(dec.Stack))
for k, v := range dec.Stack {
s.Stack[k] = uint256.Int(v)
}
} }
if dec.ReturnData != nil { if dec.ReturnData != nil {
s.ReturnData = *dec.ReturnData s.ReturnData = *dec.ReturnData

View file

@ -84,6 +84,7 @@ type structLogMarshaling struct {
GasCost math.HexOrDecimal64 GasCost math.HexOrDecimal64
Memory hexutil.Bytes Memory hexutil.Bytes
ReturnData hexutil.Bytes ReturnData hexutil.Bytes
Stack []hexutil.U256
OpName string `json:"opName"` // adds call to OpName() in MarshalJSON OpName string `json:"opName"` // adds call to OpName() in MarshalJSON
ErrorString string `json:"error,omitempty"` // adds call to ErrorString() in MarshalJSON ErrorString string `json:"error,omitempty"` // adds call to ErrorString() in MarshalJSON
} }

View file

@ -61,7 +61,6 @@ type prestateTracer struct {
env *vm.EVM env *vm.EVM
pre stateMap pre stateMap
post stateMap post stateMap
create bool
to common.Address to common.Address
config prestateTracerConfig config prestateTracerConfig
interrupt atomic.Bool // Atomic flag to signal execution interruption interrupt atomic.Bool // Atomic flag to signal execution interruption

21
go.mod
View file

@ -28,7 +28,6 @@ require (
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.6.0
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46
github.com/go-stack/stack v1.8.1
github.com/gofrs/flock v0.8.1 github.com/gofrs/flock v0.8.1
github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang/protobuf v1.5.3 github.com/golang/protobuf v1.5.3
@ -40,7 +39,7 @@ require (
github.com/hashicorp/go-bexpr v0.1.10 github.com/hashicorp/go-bexpr v0.1.10
github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7
github.com/holiman/bloomfilter/v2 v2.0.3 github.com/holiman/bloomfilter/v2 v2.0.3
github.com/holiman/uint256 v1.2.3 github.com/holiman/uint256 v1.2.4
github.com/huin/goupnp v1.3.0 github.com/huin/goupnp v1.3.0
github.com/influxdata/influxdb-client-go/v2 v2.4.0 github.com/influxdata/influxdb-client-go/v2 v2.4.0
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
@ -65,13 +64,13 @@ require (
github.com/tyler-smith/go-bip39 v1.1.0 github.com/tyler-smith/go-bip39 v1.1.0
github.com/urfave/cli/v2 v2.25.7 github.com/urfave/cli/v2 v2.25.7
go.uber.org/automaxprocs v1.5.2 go.uber.org/automaxprocs v1.5.2
golang.org/x/crypto v0.14.0 golang.org/x/crypto v0.15.0
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
golang.org/x/sync v0.4.0 golang.org/x/sync v0.5.0
golang.org/x/sys v0.13.0 golang.org/x/sys v0.14.0
golang.org/x/text v0.13.0 golang.org/x/text v0.14.0
golang.org/x/time v0.3.0 golang.org/x/time v0.3.0
golang.org/x/tools v0.13.0 golang.org/x/tools v0.15.0
google.golang.org/protobuf v1.28.0 google.golang.org/protobuf v1.28.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
@ -170,10 +169,10 @@ require (
go.uber.org/atomic v1.9.0 // indirect go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.6.0 // indirect go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.21.0 // indirect go.uber.org/zap v1.21.0 // indirect
golang.org/x/mod v0.12.0 // indirect golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.17.0 // indirect golang.org/x/net v0.18.0 // indirect
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 // indirect golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 // indirect
golang.org/x/term v0.13.0 // indirect golang.org/x/term v0.14.0 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
google.golang.org/api v0.91.0 // indirect google.golang.org/api v0.91.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect

42
go.sum
View file

@ -308,8 +308,6 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
@ -458,8 +456,8 @@ github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZ
github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
@ -817,8 +815,8 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -829,8 +827,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -857,8 +855,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -913,8 +911,8 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -950,8 +948,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1047,13 +1045,13 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1064,8 +1062,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -1134,8 +1132,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View file

@ -139,7 +139,7 @@ func TestGraphQLBlockSerialization(t *testing.T) {
// should return `estimateGas` as decimal // should return `estimateGas` as decimal
{ {
body: `{"query": "{block{ estimateGas(data:{}) }}"}`, body: `{"query": "{block{ estimateGas(data:{}) }}"}`,
want: `{"data":{"block":{"estimateGas":"0xcf08"}}}`, want: `{"data":{"block":{"estimateGas":"0xd221"}}}`,
code: 200, code: 200,
}, },
// should return `status` as decimal // should return `status` as decimal

View file

@ -29,8 +29,6 @@ import (
// NotFound is returned by API methods if the requested item does not exist. // NotFound is returned by API methods if the requested item does not exist.
var NotFound = errors.New("not found") var NotFound = errors.New("not found")
// TODO: move subscription to package event
// Subscription represents an event subscription where events are // Subscription represents an event subscription where events are
// delivered on a data channel. // delivered on a data channel.
type Subscription interface { type Subscription interface {

View file

@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/hashicorp/go-bexpr" "github.com/hashicorp/go-bexpr"
"golang.org/x/exp/slog"
) )
// Handler is the global debugging handler. // Handler is the global debugging handler.
@ -56,7 +57,7 @@ type HandlerT struct {
// Verbosity sets the log verbosity ceiling. The verbosity of individual packages // Verbosity sets the log verbosity ceiling. The verbosity of individual packages
// and source files can be raised using Vmodule. // and source files can be raised using Vmodule.
func (*HandlerT) Verbosity(level int) { func (*HandlerT) Verbosity(level int) {
glogger.Verbosity(log.Lvl(level)) glogger.Verbosity(slog.Level(level))
} }
// Vmodule sets the log verbosity pattern. See package log for details on the // Vmodule sets the log verbosity pattern. See package log for details on the
@ -65,12 +66,6 @@ func (*HandlerT) Vmodule(pattern string) error {
return glogger.Vmodule(pattern) return glogger.Vmodule(pattern)
} }
// BacktraceAt sets the log backtrace location. See package log for details on
// the pattern syntax.
func (*HandlerT) BacktraceAt(location string) error {
return glogger.BacktraceAt(location)
}
// MemStats returns detailed runtime memory statistics. // MemStats returns detailed runtime memory statistics.
func (*HandlerT) MemStats() *runtime.MemStats { func (*HandlerT) MemStats() *runtime.MemStats {
s := new(runtime.MemStats) s := new(runtime.MemStats)

View file

@ -34,6 +34,7 @@ import (
"github.com/mattn/go-colorable" "github.com/mattn/go-colorable"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"golang.org/x/exp/slog"
"gopkg.in/natefinch/lumberjack.v2" "gopkg.in/natefinch/lumberjack.v2"
) )
@ -75,17 +76,6 @@ var (
Usage: "Write logs to a file", Usage: "Write logs to a file",
Category: flags.LoggingCategory, Category: flags.LoggingCategory,
} }
backtraceAtFlag = &cli.StringFlag{
Name: "log.backtrace",
Usage: "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")",
Value: "",
Category: flags.LoggingCategory,
}
debugFlag = &cli.BoolFlag{
Name: "log.debug",
Usage: "Prepends log messages with call-site location (file and line number)",
Category: flags.LoggingCategory,
}
logRotateFlag = &cli.BoolFlag{ logRotateFlag = &cli.BoolFlag{
Name: "log.rotate", Name: "log.rotate",
Usage: "Enables log file rotation", Usage: "Enables log file rotation",
@ -160,8 +150,6 @@ var Flags = []cli.Flag{
verbosityFlag, verbosityFlag,
logVmoduleFlag, logVmoduleFlag,
vmoduleFlag, vmoduleFlag,
backtraceAtFlag,
debugFlag,
logjsonFlag, logjsonFlag,
logFormatFlag, logFormatFlag,
logFileFlag, logFileFlag,
@ -180,45 +168,34 @@ var Flags = []cli.Flag{
} }
var ( var (
glogger *log.GlogHandler glogger *log.GlogHandler
logOutputStream log.Handler logOutputFile io.WriteCloser
defaultTerminalHandler *log.TerminalHandler
) )
func init() { func init() {
glogger = log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) defaultTerminalHandler = log.NewTerminalHandler(os.Stderr, false)
glogger = log.NewGlogHandler(defaultTerminalHandler)
glogger.Verbosity(log.LvlInfo) glogger.Verbosity(log.LvlInfo)
log.Root().SetHandler(glogger) log.SetDefault(log.NewLogger(glogger))
}
func ResetLogging() {
if defaultTerminalHandler != nil {
defaultTerminalHandler.ResetFieldPadding()
}
} }
// Setup initializes profiling and logging based on the CLI flags. // Setup initializes profiling and logging based on the CLI flags.
// It should be called as early as possible in the program. // It should be called as early as possible in the program.
func Setup(ctx *cli.Context) error { func Setup(ctx *cli.Context) error {
var ( var (
logfmt log.Format handler slog.Handler
output = io.Writer(os.Stderr) terminalOutput = io.Writer(os.Stderr)
logFmtFlag = ctx.String(logFormatFlag.Name) output io.Writer
logFmtFlag = ctx.String(logFormatFlag.Name)
) )
switch {
case ctx.Bool(logjsonFlag.Name):
// Retain backwards compatibility with `--log.json` flag if `--log.format` not set
defer log.Warn("The flag '--log.json' is deprecated, please use '--log.format=json' instead")
logfmt = log.JSONFormat()
case logFmtFlag == "json":
logfmt = log.JSONFormat()
case logFmtFlag == "logfmt":
logfmt = log.LogfmtFormat()
case logFmtFlag == "", logFmtFlag == "terminal":
useColor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
if useColor {
output = colorable.NewColorableStderr()
}
logfmt = log.TerminalFormat(useColor)
default:
// Unknown log format specified
return fmt.Errorf("unknown log format: %v", ctx.String(logFormatFlag.Name))
}
var ( var (
ostream = log.StreamHandler(output, logfmt)
logFile = ctx.String(logFileFlag.Name) logFile = ctx.String(logFileFlag.Name)
rotation = ctx.Bool(logRotateFlag.Name) rotation = ctx.Bool(logRotateFlag.Name)
) )
@ -241,27 +218,55 @@ func Setup(ctx *cli.Context) error {
} else { } else {
context = append(context, "location", filepath.Join(os.TempDir(), "geth-lumberjack.log")) context = append(context, "location", filepath.Join(os.TempDir(), "geth-lumberjack.log"))
} }
lumberWriter := &lumberjack.Logger{ logOutputFile = &lumberjack.Logger{
Filename: logFile, Filename: logFile,
MaxSize: ctx.Int(logMaxSizeMBsFlag.Name), MaxSize: ctx.Int(logMaxSizeMBsFlag.Name),
MaxBackups: ctx.Int(logMaxBackupsFlag.Name), MaxBackups: ctx.Int(logMaxBackupsFlag.Name),
MaxAge: ctx.Int(logMaxAgeFlag.Name), MaxAge: ctx.Int(logMaxAgeFlag.Name),
Compress: ctx.Bool(logCompressFlag.Name), Compress: ctx.Bool(logCompressFlag.Name),
} }
ostream = log.StreamHandler(io.MultiWriter(output, lumberWriter), logfmt) output = io.MultiWriter(terminalOutput, logOutputFile)
} else if logFile != "" { } else if logFile != "" {
f, err := os.OpenFile(logFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) var err error
if err != nil { if logOutputFile, err = os.OpenFile(logFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644); err != nil {
return err return err
} }
ostream = log.StreamHandler(io.MultiWriter(output, f), logfmt) output = io.MultiWriter(logOutputFile, terminalOutput)
context = append(context, "location", logFile) context = append(context, "location", logFile)
} else {
output = terminalOutput
} }
glogger.SetHandler(ostream)
switch {
case ctx.Bool(logjsonFlag.Name):
// Retain backwards compatibility with `--log.json` flag if `--log.format` not set
defer log.Warn("The flag '--log.json' is deprecated, please use '--log.format=json' instead")
handler = log.JSONHandler(output)
case logFmtFlag == "json":
handler = log.JSONHandler(output)
case logFmtFlag == "logfmt":
handler = log.LogfmtHandler(output)
case logFmtFlag == "", logFmtFlag == "terminal":
useColor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
if useColor {
terminalOutput = colorable.NewColorableStderr()
if logOutputFile != nil {
output = io.MultiWriter(logOutputFile, terminalOutput)
} else {
output = terminalOutput
}
}
handler = log.NewTerminalHandler(output, useColor)
default:
// Unknown log format specified
return fmt.Errorf("unknown log format: %v", ctx.String(logFormatFlag.Name))
}
glogger = log.NewGlogHandler(handler)
// logging // logging
verbosity := ctx.Int(verbosityFlag.Name) verbosity := log.FromLegacyLevel(ctx.Int(verbosityFlag.Name))
glogger.Verbosity(log.Lvl(verbosity)) glogger.Verbosity(verbosity)
vmodule := ctx.String(logVmoduleFlag.Name) vmodule := ctx.String(logVmoduleFlag.Name)
if vmodule == "" { if vmodule == "" {
// Retain backwards compatibility with `--vmodule` flag if `--log.vmodule` not set // Retain backwards compatibility with `--vmodule` flag if `--log.vmodule` not set
@ -272,16 +277,7 @@ func Setup(ctx *cli.Context) error {
} }
glogger.Vmodule(vmodule) glogger.Vmodule(vmodule)
debug := ctx.Bool(debugFlag.Name) log.SetDefault(log.NewLogger(glogger))
if ctx.IsSet(debugFlag.Name) {
debug = ctx.Bool(debugFlag.Name)
}
log.PrintOrigins(debug)
backtrace := ctx.String(backtraceAtFlag.Name)
glogger.BacktraceAt(backtrace)
log.Root().SetHandler(glogger)
// profiling, tracing // profiling, tracing
runtime.MemProfileRate = memprofilerateFlag.Value runtime.MemProfileRate = memprofilerateFlag.Value
@ -341,8 +337,8 @@ func StartPProf(address string, withMetrics bool) {
func Exit() { func Exit() {
Handler.StopCPUProfile() Handler.StopCPUProfile()
Handler.StopGoTrace() Handler.StopGoTrace()
if closer, ok := logOutputStream.(io.Closer); ok { if logOutputFile != nil {
closer.Close() logOutputFile.Close()
} }
} }

View file

@ -40,6 +40,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "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/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/gasestimator"
"github.com/ethereum/go-ethereum/eth/tracers/logger" "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/p2p" "github.com/ethereum/go-ethereum/p2p"
@ -50,6 +51,10 @@ import (
"github.com/tyler-smith/go-bip39" "github.com/tyler-smith/go-bip39"
) )
// estimateGasErrorRatio is the amount of overestimation eth_estimateGas is
// allowed to produce in order to speed up calculations.
const estimateGasErrorRatio = 0.015
// EthereumAPI provides an API to access Ethereum related information. // EthereumAPI provides an API to access Ethereum related information.
type EthereumAPI struct { type EthereumAPI struct {
b Backend b Backend
@ -1083,7 +1088,7 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S
if blockOverrides != nil { if blockOverrides != nil {
blockOverrides.Apply(&blockCtx) blockOverrides.Apply(&blockCtx)
} }
evm, vmError := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, &blockCtx) evm := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, &blockCtx)
// Wait for the context to be done and cancel the evm. Even if the // Wait for the context to be done and cancel the evm. Even if the
// EVM has finished, cancelling may be done (repeatedly) // EVM has finished, cancelling may be done (repeatedly)
@ -1095,7 +1100,7 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S
// Execute the message. // Execute the message.
gp := new(core.GasPool).AddGas(math.MaxUint64) gp := new(core.GasPool).AddGas(math.MaxUint64)
result, err := core.ApplyMessage(evm, msg, gp) result, err := core.ApplyMessage(evm, msg, gp)
if err := vmError(); err != nil { if err := state.Error(); err != nil {
return nil, err return nil, err
} }
@ -1120,15 +1125,16 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap) return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap)
} }
func newRevertError(result *core.ExecutionResult) *revertError { func newRevertError(revert []byte) *revertError {
reason, errUnpack := abi.UnpackRevert(result.Revert()) err := vm.ErrExecutionReverted
err := errors.New("execution reverted")
reason, errUnpack := abi.UnpackRevert(revert)
if errUnpack == nil { if errUnpack == nil {
err = fmt.Errorf("execution reverted: %v", reason) err = fmt.Errorf("%w: %v", vm.ErrExecutionReverted, reason)
} }
return &revertError{ return &revertError{
error: err, error: err,
reason: hexutil.Encode(result.Revert()), reason: hexutil.Encode(revert),
} }
} }
@ -1167,147 +1173,45 @@ func (s *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrO
} }
// If the result contains a revert reason, try to unpack and return it. // If the result contains a revert reason, try to unpack and return it.
if len(result.Revert()) > 0 { if len(result.Revert()) > 0 {
return nil, newRevertError(result) return nil, newRevertError(result.Revert())
} }
return result.Return(), result.Err return result.Return(), result.Err
} }
// executeEstimate is a helper that executes the transaction under a given gas limit and returns
// true if the transaction fails for a reason that might be related to not enough gas. A non-nil
// error means execution failed due to reasons unrelated to the gas limit.
func executeEstimate(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, gasCap uint64, gasLimit uint64) (bool, *core.ExecutionResult, error) {
args.Gas = (*hexutil.Uint64)(&gasLimit)
result, err := doCall(ctx, b, args, state, header, nil, nil, 0, gasCap)
if err != nil {
if errors.Is(err, core.ErrIntrinsicGas) {
return true, nil, nil // Special case, raise gas limit
}
return true, nil, err // Bail out
}
return result.Failed(), result, nil
}
// DoEstimateGas returns the lowest possible gas limit that allows the transaction to run // DoEstimateGas returns the lowest possible gas limit that allows the transaction to run
// successfully at block `blockNrOrHash`. It returns error if the transaction would revert, or if // successfully at block `blockNrOrHash`. It returns error if the transaction would revert, or if
// there are unexpected failures. The gas limit is capped by both `args.Gas` (if non-nil & // there are unexpected failures. The gas limit is capped by both `args.Gas` (if non-nil &
// non-zero) and `gasCap` (if non-zero). // non-zero) and `gasCap` (if non-zero).
func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, gasCap uint64) (hexutil.Uint64, error) { func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, gasCap uint64) (hexutil.Uint64, error) {
// Binary search the gas limit, as it may need to be higher than the amount used // Retrieve the base state and mutate it with any overrides
var (
lo uint64 // lowest-known gas limit where tx execution fails
hi uint64 // lowest-known gas limit where tx execution succeeds
)
// Use zero address if sender unspecified.
if args.From == nil {
args.From = new(common.Address)
}
// Determine the highest gas limit can be used during the estimation.
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
hi = uint64(*args.Gas)
} else {
// Retrieve the block to act as the gas ceiling
block, err := b.BlockByNumberOrHash(ctx, blockNrOrHash)
if err != nil {
return 0, err
}
if block == nil {
return 0, errors.New("block not found")
}
hi = block.GasLimit()
}
// Normalize the max fee per gas the call is willing to spend.
var feeCap *big.Int
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
return 0, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
} else if args.GasPrice != nil {
feeCap = args.GasPrice.ToInt()
} else if args.MaxFeePerGas != nil {
feeCap = args.MaxFeePerGas.ToInt()
} else {
feeCap = common.Big0
}
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if state == nil || err != nil { if state == nil || err != nil {
return 0, err return 0, err
} }
if err := overrides.Apply(state); err != nil { if err = overrides.Apply(state); err != nil {
return 0, err return 0, err
} }
// Construct the gas estimator option from the user input
// Recap the highest gas limit with account's available balance. opts := &gasestimator.Options{
if feeCap.BitLen() != 0 { Config: b.ChainConfig(),
balance := state.GetBalance(*args.From) // from can't be nil Chain: NewChainContext(ctx, b),
available := new(big.Int).Set(balance) Header: header,
if args.Value != nil { State: state,
if args.Value.ToInt().Cmp(available) >= 0 { ErrorRatio: estimateGasErrorRatio,
return 0, core.ErrInsufficientFundsForTransfer
}
available.Sub(available, args.Value.ToInt())
}
allowance := new(big.Int).Div(available, feeCap)
// If the allowance is larger than maximum uint64, skip checking
if allowance.IsUint64() && hi > allowance.Uint64() {
transfer := args.Value
if transfer == nil {
transfer = new(hexutil.Big)
}
log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance,
"sent", transfer.ToInt(), "maxFeePerGas", feeCap, "fundable", allowance)
hi = allowance.Uint64()
}
} }
// Recap the highest gas allowance with specified gascap. // Run the gas estimation andwrap any revertals into a custom return
if gasCap != 0 && hi > gasCap { call, err := args.ToMessage(gasCap, header.BaseFee)
log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
hi = gasCap
}
// We first execute the transaction at the highest allowable gas limit, since if this fails we
// can return error immediately.
failed, result, err := executeEstimate(ctx, b, args, state.Copy(), header, gasCap, hi)
if err != nil { if err != nil {
return 0, err return 0, err
} }
if failed { estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap)
if result != nil && !errors.Is(result.Err, vm.ErrOutOfGas) { if err != nil {
if len(result.Revert()) > 0 { if len(revert) > 0 {
return 0, newRevertError(result) return 0, newRevertError(revert)
}
return 0, result.Err
} }
return 0, fmt.Errorf("gas required exceeds allowance (%d)", hi) return 0, err
} }
// For almost any transaction, the gas consumed by the unconstrained execution above return hexutil.Uint64(estimate), nil
// lower-bounds the gas limit required for it to succeed. One exception is those txs that
// explicitly check gas remaining in order to successfully execute within a given limit, but we
// probably don't want to return a lowest possible gas limit for these cases anyway.
lo = result.UsedGas - 1
// Binary search for the smallest gas limit that allows the tx to execute successfully.
for lo+1 < hi {
mid := (hi + lo) / 2
if mid > lo*2 {
// Most txs don't need much higher gas limit than their gas used, and most txs don't
// require near the full block limit of gas, so the selection of where to bisect the
// range here is skewed to favor the low side.
mid = lo * 2
}
failed, _, err = executeEstimate(ctx, b, args, state.Copy(), header, gasCap, mid)
if err != nil {
// This should not happen under normal conditions since if we make it this far the
// transaction had run without error at least once before.
log.Error("execution error in estimate gas", "err", err)
return 0, err
}
if failed {
lo = mid
} else {
hi = mid
}
}
return hexutil.Uint64(hi), nil
} }
// EstimateGas returns the lowest possible gas limit that allows the transaction to run // EstimateGas returns the lowest possible gas limit that allows the transaction to run
@ -1640,7 +1544,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
// Apply the transaction with the access list tracer // Apply the transaction with the access list tracer
tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles)
config := vm.Config{Tracer: tracer, NoBaseFee: true} config := vm.Config{Tracer: tracer, NoBaseFee: true}
vmenv, _ := b.GetEVM(ctx, msg, statedb, header, &config, nil) vmenv := b.GetEVM(ctx, msg, statedb, header, &config, nil)
res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
if err != nil { if err != nil {
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err) return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err)

View file

@ -536,8 +536,7 @@ func (b testBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
} }
return big.NewInt(1) return big.NewInt(1)
} }
func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) (*vm.EVM, func() error) { func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) *vm.EVM {
vmError := func() error { return nil }
if vmConfig == nil { if vmConfig == nil {
vmConfig = b.chain.GetVMConfig() vmConfig = b.chain.GetVMConfig()
} }
@ -546,7 +545,7 @@ func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state
if blockContext != nil { if blockContext != nil {
context = *blockContext context = *blockContext
} }
return vm.NewEVM(context, txContext, state, b.chain.Config(), *vmConfig), vmError return vm.NewEVM(context, txContext, state, b.chain.Config(), *vmConfig)
} }
func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
panic("implement me") panic("implement me")
@ -736,7 +735,7 @@ func TestEstimateGas(t *testing.T) {
t.Errorf("test %d: want no error, have %v", i, err) t.Errorf("test %d: want no error, have %v", i, err)
continue continue
} }
if uint64(result) != tc.want { if float64(result) > float64(tc.want)*(1+estimateGasErrorRatio) {
t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, uint64(result), tc.want) t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, uint64(result), tc.want)
} }
} }
@ -911,18 +910,18 @@ func TestCall(t *testing.T) {
} }
} }
type Account struct { type account struct {
key *ecdsa.PrivateKey key *ecdsa.PrivateKey
addr common.Address addr common.Address
} }
func newAccounts(n int) (accounts []Account) { func newAccounts(n int) (accounts []account) {
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
addr := crypto.PubkeyToAddress(key.PublicKey) addr := crypto.PubkeyToAddress(key.PublicKey)
accounts = append(accounts, Account{key: key, addr: addr}) accounts = append(accounts, account{key: key, addr: addr})
} }
slices.SortFunc(accounts, func(a, b Account) int { return a.addr.Cmp(b.addr) }) slices.SortFunc(accounts, func(a, b account) int { return a.addr.Cmp(b.addr) })
return accounts return accounts
} }

View file

@ -68,7 +68,7 @@ type Backend interface {
PendingBlockAndReceipts() (*types.Block, types.Receipts) PendingBlockAndReceipts() (*types.Block, types.Receipts)
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
GetTd(ctx context.Context, hash common.Hash) *big.Int GetTd(ctx context.Context, hash common.Hash) *big.Int
GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription

View file

@ -305,8 +305,8 @@ func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number
return nil, nil return nil, nil
} }
func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil } func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil }
func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error) { func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM {
return nil, nil return nil
} }
func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil } func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil }
func (b *backendMock) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription { func (b *backendMock) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {

View file

@ -18,26 +18,19 @@
package testlog package testlog
import ( import (
"bytes"
"context"
"fmt"
"sync" "sync"
"testing" "testing"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"golang.org/x/exp/slog"
) )
// Handler returns a log handler which logs to the unit test log of t. const (
func Handler(t *testing.T, level log.Lvl) log.Handler { termTimeFormat = "01-02|15:04:05.000"
return log.LvlFilterHandler(level, &handler{t, log.TerminalFormat(false)}) )
}
type handler struct {
t *testing.T
fmt log.Format
}
func (h *handler) Log(r *log.Record) error {
h.t.Logf("%s", h.fmt.Format(r))
return nil
}
// logger implements log.Logger such that all output goes to the unit test log via // logger implements log.Logger such that all output goes to the unit test log via
// t.Logf(). All methods in between logger.Trace, logger.Debug, etc. are marked as test // t.Logf(). All methods in between logger.Trace, logger.Debug, etc. are marked as test
@ -51,25 +44,64 @@ type logger struct {
} }
type bufHandler struct { type bufHandler struct {
buf []*log.Record buf []slog.Record
fmt log.Format attrs []slog.Attr
level slog.Level
} }
func (h *bufHandler) Log(r *log.Record) error { func (h *bufHandler) Handle(_ context.Context, r slog.Record) error {
h.buf = append(h.buf, r) h.buf = append(h.buf, r)
return nil return nil
} }
// Logger returns a logger which logs to the unit test log of t. func (h *bufHandler) Enabled(_ context.Context, lvl slog.Level) bool {
func Logger(t *testing.T, level log.Lvl) log.Logger { return lvl <= h.level
l := &logger{ }
t: t,
l: log.New(), func (h *bufHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
mu: new(sync.Mutex), records := make([]slog.Record, len(h.buf))
h: &bufHandler{fmt: log.TerminalFormat(false)}, copy(records[:], h.buf[:])
return &bufHandler{
records,
append(h.attrs, attrs...),
h.level,
} }
l.l.SetHandler(log.LvlFilterHandler(level, l.h)) }
return l
func (h *bufHandler) WithGroup(_ string) slog.Handler {
panic("not implemented")
}
// Logger returns a logger which logs to the unit test log of t.
func Logger(t *testing.T, level slog.Level) log.Logger {
handler := bufHandler{
[]slog.Record{},
[]slog.Attr{},
level,
}
return &logger{
t: t,
l: log.NewLogger(&handler),
mu: new(sync.Mutex),
h: &handler,
}
}
// LoggerWithHandler returns
func LoggerWithHandler(t *testing.T, handler slog.Handler) log.Logger {
var bh bufHandler
return &logger{
t: t,
l: log.NewLogger(handler),
mu: new(sync.Mutex),
h: &bh,
}
}
func (l *logger) Write(level slog.Level, msg string, ctx ...interface{}) {}
func (l *logger) Enabled(ctx context.Context, level slog.Level) bool {
return l.l.Enabled(ctx, level)
} }
func (l *logger) Trace(msg string, ctx ...interface{}) { func (l *logger) Trace(msg string, ctx ...interface{}) {
@ -80,6 +112,14 @@ func (l *logger) Trace(msg string, ctx ...interface{}) {
l.flush() l.flush()
} }
func (l *logger) Log(level slog.Level, msg string, ctx ...interface{}) {
l.t.Helper()
l.mu.Lock()
defer l.mu.Unlock()
l.l.Log(level, msg, ctx...)
l.flush()
}
func (l *logger) Debug(msg string, ctx ...interface{}) { func (l *logger) Debug(msg string, ctx ...interface{}) {
l.t.Helper() l.t.Helper()
l.mu.Lock() l.mu.Lock()
@ -120,23 +160,44 @@ func (l *logger) Crit(msg string, ctx ...interface{}) {
l.flush() l.flush()
} }
func (l *logger) With(ctx ...interface{}) log.Logger {
return &logger{l.t, l.l.With(ctx...), l.mu, l.h}
}
func (l *logger) New(ctx ...interface{}) log.Logger { func (l *logger) New(ctx ...interface{}) log.Logger {
return &logger{l.t, l.l.New(ctx...), l.mu, l.h} return l.With(ctx...)
} }
func (l *logger) GetHandler() log.Handler { // terminalFormat formats a message similarly to the NewTerminalHandler in the log package.
return l.l.GetHandler() // The difference is that terminalFormat does not escape messages/attributes and does not pad attributes.
} func (h *bufHandler) terminalFormat(r slog.Record) string {
buf := &bytes.Buffer{}
lvl := log.LevelAlignedString(r.Level)
attrs := []slog.Attr{}
r.Attrs(func(attr slog.Attr) bool {
attrs = append(attrs, attr)
return true
})
func (l *logger) SetHandler(h log.Handler) { attrs = append(h.attrs, attrs...)
l.l.SetHandler(h)
fmt.Fprintf(buf, "%s[%s] %s ", lvl, r.Time.Format(termTimeFormat), r.Message)
if length := len(r.Message); length < 40 {
buf.Write(bytes.Repeat([]byte{' '}, 40-length))
}
for _, attr := range attrs {
fmt.Fprintf(buf, " %s=%s", attr.Key, string(log.FormatSlogValue(attr.Value, nil)))
}
buf.WriteByte('\n')
return buf.String()
} }
// flush writes all buffered messages and clears the buffer. // flush writes all buffered messages and clears the buffer.
func (l *logger) flush() { func (l *logger) flush() {
l.t.Helper() l.t.Helper()
for _, r := range l.h.buf { for _, r := range l.h.buf {
l.t.Logf("%s", l.h.fmt.Format(r)) l.t.Logf("%s", l.h.terminalFormat(r))
} }
l.h.buf = nil l.h.buf = nil
} }

View file

@ -1,531 +0,0 @@
// Copyright 2016 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 light implements on-demand retrieval capable state and chain objects
// for the Ethereum Light Client.
package light
import (
"context"
"errors"
"math/big"
"sync"
"sync/atomic"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/lru"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)
var (
bodyCacheLimit = 256
blockCacheLimit = 256
)
// LightChain represents a canonical chain that by default only handles block
// headers, downloading block bodies and receipts on demand through an ODR
// interface. It only does header validation during chain insertion.
type LightChain struct {
hc *core.HeaderChain
indexerConfig *IndexerConfig
chainDb ethdb.Database
engine consensus.Engine
odr OdrBackend
chainFeed event.Feed
chainSideFeed event.Feed
chainHeadFeed event.Feed
scope event.SubscriptionScope
genesisBlock *types.Block
forker *core.ForkChoice
bodyCache *lru.Cache[common.Hash, *types.Body]
bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue]
blockCache *lru.Cache[common.Hash, *types.Block]
chainmu sync.RWMutex // protects header inserts
quit chan struct{}
wg sync.WaitGroup
// Atomic boolean switches:
stopped atomic.Bool // whether LightChain is stopped or running
procInterrupt atomic.Bool // interrupts chain insert
}
// NewLightChain returns a fully initialised light chain using information
// available in the database. It initialises the default Ethereum header
// validator.
func NewLightChain(odr OdrBackend, config *params.ChainConfig, engine consensus.Engine) (*LightChain, error) {
bc := &LightChain{
chainDb: odr.Database(),
indexerConfig: odr.IndexerConfig(),
odr: odr,
quit: make(chan struct{}),
bodyCache: lru.NewCache[common.Hash, *types.Body](bodyCacheLimit),
bodyRLPCache: lru.NewCache[common.Hash, rlp.RawValue](bodyCacheLimit),
blockCache: lru.NewCache[common.Hash, *types.Block](blockCacheLimit),
engine: engine,
}
bc.forker = core.NewForkChoice(bc, nil)
var err error
bc.hc, err = core.NewHeaderChain(odr.Database(), config, bc.engine, bc.getProcInterrupt)
if err != nil {
return nil, err
}
bc.genesisBlock, _ = bc.GetBlockByNumber(NoOdr, 0)
if bc.genesisBlock == nil {
return nil, core.ErrNoGenesis
}
if err := bc.loadLastState(); err != nil {
return nil, err
}
// Check the current state of the block hashes and make sure that we do not have any of the bad blocks in our chain
for hash := range core.BadHashes {
if header := bc.GetHeaderByHash(hash); header != nil {
log.Error("Found bad hash, rewinding chain", "number", header.Number, "hash", header.ParentHash)
bc.SetHead(header.Number.Uint64() - 1)
log.Info("Chain rewind was successful, resuming normal operation")
}
}
return bc, nil
}
func (lc *LightChain) getProcInterrupt() bool {
return lc.procInterrupt.Load()
}
// Odr returns the ODR backend of the chain
func (lc *LightChain) Odr() OdrBackend {
return lc.odr
}
// HeaderChain returns the underlying header chain.
func (lc *LightChain) HeaderChain() *core.HeaderChain {
return lc.hc
}
// loadLastState loads the last known chain state from the database. This method
// assumes that the chain manager mutex is held.
func (lc *LightChain) loadLastState() error {
if head := rawdb.ReadHeadHeaderHash(lc.chainDb); head == (common.Hash{}) {
// Corrupt or empty database, init from scratch
lc.Reset()
} else {
header := lc.GetHeaderByHash(head)
if header == nil {
// Corrupt or empty database, init from scratch
lc.Reset()
} else {
lc.hc.SetCurrentHeader(header)
}
}
// Issue a status log and return
header := lc.hc.CurrentHeader()
headerTd := lc.GetTd(header.Hash(), header.Number.Uint64())
log.Info("Loaded most recent local header", "number", header.Number, "hash", header.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(int64(header.Time), 0)))
return nil
}
// SetHead rewinds the local chain to a new head. Everything above the new
// head will be deleted and the new one set.
func (lc *LightChain) SetHead(head uint64) error {
lc.chainmu.Lock()
defer lc.chainmu.Unlock()
lc.hc.SetHead(head, nil, nil)
return lc.loadLastState()
}
// SetHeadWithTimestamp rewinds the local chain to a new head that has at max
// the given timestamp. Everything above the new head will be deleted and the
// new one set.
func (lc *LightChain) SetHeadWithTimestamp(timestamp uint64) error {
lc.chainmu.Lock()
defer lc.chainmu.Unlock()
lc.hc.SetHeadWithTimestamp(timestamp, nil, nil)
return lc.loadLastState()
}
// GasLimit returns the gas limit of the current HEAD block.
func (lc *LightChain) GasLimit() uint64 {
return lc.hc.CurrentHeader().GasLimit
}
// Reset purges the entire blockchain, restoring it to its genesis state.
func (lc *LightChain) Reset() {
lc.ResetWithGenesisBlock(lc.genesisBlock)
}
// ResetWithGenesisBlock purges the entire blockchain, restoring it to the
// specified genesis state.
func (lc *LightChain) ResetWithGenesisBlock(genesis *types.Block) {
// Dump the entire block chain and purge the caches
lc.SetHead(0)
lc.chainmu.Lock()
defer lc.chainmu.Unlock()
// Prepare the genesis block and reinitialise the chain
batch := lc.chainDb.NewBatch()
rawdb.WriteTd(batch, genesis.Hash(), genesis.NumberU64(), genesis.Difficulty())
rawdb.WriteBlock(batch, genesis)
rawdb.WriteHeadHeaderHash(batch, genesis.Hash())
if err := batch.Write(); err != nil {
log.Crit("Failed to reset genesis block", "err", err)
}
lc.genesisBlock = genesis
lc.hc.SetGenesis(lc.genesisBlock.Header())
lc.hc.SetCurrentHeader(lc.genesisBlock.Header())
}
// Accessors
// Engine retrieves the light chain's consensus engine.
func (lc *LightChain) Engine() consensus.Engine { return lc.engine }
// Genesis returns the genesis block
func (lc *LightChain) Genesis() *types.Block {
return lc.genesisBlock
}
func (lc *LightChain) StateCache() state.Database {
panic("not implemented")
}
// GetBody retrieves a block body (transactions and uncles) from the database
// or ODR service by hash, caching it if found.
func (lc *LightChain) GetBody(ctx context.Context, hash common.Hash) (*types.Body, error) {
// Short circuit if the body's already in the cache, retrieve otherwise
if cached, ok := lc.bodyCache.Get(hash); ok {
return cached, nil
}
number := lc.hc.GetBlockNumber(hash)
if number == nil {
return nil, errors.New("unknown block")
}
body, err := GetBody(ctx, lc.odr, hash, *number)
if err != nil {
return nil, err
}
// Cache the found body for next time and return
lc.bodyCache.Add(hash, body)
return body, nil
}
// GetBodyRLP retrieves a block body in RLP encoding from the database or
// ODR service by hash, caching it if found.
func (lc *LightChain) GetBodyRLP(ctx context.Context, hash common.Hash) (rlp.RawValue, error) {
// Short circuit if the body's already in the cache, retrieve otherwise
if cached, ok := lc.bodyRLPCache.Get(hash); ok {
return cached, nil
}
number := lc.hc.GetBlockNumber(hash)
if number == nil {
return nil, errors.New("unknown block")
}
body, err := GetBodyRLP(ctx, lc.odr, hash, *number)
if err != nil {
return nil, err
}
// Cache the found body for next time and return
lc.bodyRLPCache.Add(hash, body)
return body, nil
}
// HasBlock checks if a block is fully present in the database or not, caching
// it if present.
func (lc *LightChain) HasBlock(hash common.Hash, number uint64) bool {
blk, _ := lc.GetBlock(NoOdr, hash, number)
return blk != nil
}
// GetBlock retrieves a block from the database or ODR service by hash and number,
// caching it if found.
func (lc *LightChain) GetBlock(ctx context.Context, hash common.Hash, number uint64) (*types.Block, error) {
// Short circuit if the block's already in the cache, retrieve otherwise
if block, ok := lc.blockCache.Get(hash); ok {
return block, nil
}
block, err := GetBlock(ctx, lc.odr, hash, number)
if err != nil {
return nil, err
}
// Cache the found block for next time and return
lc.blockCache.Add(block.Hash(), block)
return block, nil
}
// GetBlockByHash retrieves a block from the database or ODR service by hash,
// caching it if found.
func (lc *LightChain) GetBlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
number := lc.hc.GetBlockNumber(hash)
if number == nil {
return nil, errors.New("unknown block")
}
return lc.GetBlock(ctx, hash, *number)
}
// GetBlockByNumber retrieves a block from the database or ODR service by
// number, caching it (associated with its hash) if found.
func (lc *LightChain) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) {
hash, err := GetCanonicalHash(ctx, lc.odr, number)
if hash == (common.Hash{}) || err != nil {
return nil, err
}
return lc.GetBlock(ctx, hash, number)
}
// Stop stops the blockchain service. If any imports are currently in progress
// it will abort them using the procInterrupt.
func (lc *LightChain) Stop() {
if !lc.stopped.CompareAndSwap(false, true) {
return
}
close(lc.quit)
lc.StopInsert()
lc.wg.Wait()
log.Info("Blockchain stopped")
}
// StopInsert interrupts all insertion methods, causing them to return
// errInsertionInterrupted as soon as possible. Insertion is permanently disabled after
// calling this method.
func (lc *LightChain) StopInsert() {
lc.procInterrupt.Store(true)
}
// Rollback is designed to remove a chain of links from the database that aren't
// certain enough to be valid.
func (lc *LightChain) Rollback(chain []common.Hash) {
lc.chainmu.Lock()
defer lc.chainmu.Unlock()
batch := lc.chainDb.NewBatch()
for i := len(chain) - 1; i >= 0; i-- {
hash := chain[i]
// Degrade the chain markers if they are explicitly reverted.
// In theory we should update all in-memory markers in the
// last step, however the direction of rollback is from high
// to low, so it's safe the update in-memory markers directly.
if head := lc.hc.CurrentHeader(); head.Hash() == hash {
rawdb.WriteHeadHeaderHash(batch, head.ParentHash)
lc.hc.SetCurrentHeader(lc.GetHeader(head.ParentHash, head.Number.Uint64()-1))
}
}
if err := batch.Write(); err != nil {
log.Crit("Failed to rollback light chain", "error", err)
}
}
func (lc *LightChain) InsertHeader(header *types.Header) error {
// Verify the header first before obtaining the lock
headers := []*types.Header{header}
if _, err := lc.hc.ValidateHeaderChain(headers); err != nil {
return err
}
// Make sure only one thread manipulates the chain at once
lc.chainmu.Lock()
defer lc.chainmu.Unlock()
lc.wg.Add(1)
defer lc.wg.Done()
_, err := lc.hc.WriteHeaders(headers)
log.Info("Inserted header", "number", header.Number, "hash", header.Hash())
return err
}
func (lc *LightChain) SetCanonical(header *types.Header) error {
lc.chainmu.Lock()
defer lc.chainmu.Unlock()
lc.wg.Add(1)
defer lc.wg.Done()
if err := lc.hc.Reorg([]*types.Header{header}); err != nil {
return err
}
// Emit events
block := types.NewBlockWithHeader(header)
lc.chainFeed.Send(core.ChainEvent{Block: block, Hash: block.Hash()})
lc.chainHeadFeed.Send(core.ChainHeadEvent{Block: block})
log.Info("Set the chain head", "number", block.Number(), "hash", block.Hash())
return nil
}
// InsertHeaderChain attempts to insert the given header chain in to the local
// chain, possibly creating a reorg. If an error is returned, it will return the
// index number of the failing header as well an error describing what went wrong.
// In the case of a light chain, InsertHeaderChain also creates and posts light
// chain events when necessary.
func (lc *LightChain) InsertHeaderChain(chain []*types.Header) (int, error) {
if len(chain) == 0 {
return 0, nil
}
start := time.Now()
if i, err := lc.hc.ValidateHeaderChain(chain); err != nil {
return i, err
}
// Make sure only one thread manipulates the chain at once
lc.chainmu.Lock()
defer lc.chainmu.Unlock()
lc.wg.Add(1)
defer lc.wg.Done()
status, err := lc.hc.InsertHeaderChain(chain, start, lc.forker)
if err != nil || len(chain) == 0 {
return 0, err
}
// Create chain event for the new head block of this insertion.
var (
lastHeader = chain[len(chain)-1]
block = types.NewBlockWithHeader(lastHeader)
)
switch status {
case core.CanonStatTy:
lc.chainFeed.Send(core.ChainEvent{Block: block, Hash: block.Hash()})
lc.chainHeadFeed.Send(core.ChainHeadEvent{Block: block})
case core.SideStatTy:
lc.chainSideFeed.Send(core.ChainSideEvent{Block: block})
}
return 0, err
}
// CurrentHeader retrieves the current head header of the canonical chain. The
// header is retrieved from the HeaderChain's internal cache.
func (lc *LightChain) CurrentHeader() *types.Header {
return lc.hc.CurrentHeader()
}
// GetTd retrieves a block's total difficulty in the canonical chain from the
// database by hash and number, caching it if found.
func (lc *LightChain) GetTd(hash common.Hash, number uint64) *big.Int {
return lc.hc.GetTd(hash, number)
}
// GetTdOdr retrieves the total difficult from the database or
// network by hash and number, caching it (associated with its hash) if found.
func (lc *LightChain) GetTdOdr(ctx context.Context, hash common.Hash, number uint64) *big.Int {
td := lc.GetTd(hash, number)
if td != nil {
return td
}
td, _ = GetTd(ctx, lc.odr, hash, number)
return td
}
// GetHeader retrieves a block header from the database by hash and number,
// caching it if found.
func (lc *LightChain) GetHeader(hash common.Hash, number uint64) *types.Header {
return lc.hc.GetHeader(hash, number)
}
// GetHeaderByHash retrieves a block header from the database by hash, caching it if
// found.
func (lc *LightChain) GetHeaderByHash(hash common.Hash) *types.Header {
return lc.hc.GetHeaderByHash(hash)
}
// HasHeader checks if a block header is present in the database or not, caching
// it if present.
func (lc *LightChain) HasHeader(hash common.Hash, number uint64) bool {
return lc.hc.HasHeader(hash, number)
}
// GetCanonicalHash returns the canonical hash for a given block number
func (bc *LightChain) GetCanonicalHash(number uint64) common.Hash {
return bc.hc.GetCanonicalHash(number)
}
// GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or
// a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the
// number of blocks to be individually checked before we reach the canonical chain.
//
// Note: ancestor == 0 returns the same block, 1 returns its parent and so on.
func (lc *LightChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) {
return lc.hc.GetAncestor(hash, number, ancestor, maxNonCanonical)
}
// GetHeaderByNumber retrieves a block header from the database by number,
// caching it (associated with its hash) if found.
func (lc *LightChain) GetHeaderByNumber(number uint64) *types.Header {
return lc.hc.GetHeaderByNumber(number)
}
// GetHeaderByNumberOdr retrieves a block header from the database or network
// by number, caching it (associated with its hash) if found.
func (lc *LightChain) GetHeaderByNumberOdr(ctx context.Context, number uint64) (*types.Header, error) {
if header := lc.hc.GetHeaderByNumber(number); header != nil {
return header, nil
}
return GetHeaderByNumber(ctx, lc.odr, number)
}
// Config retrieves the header chain's chain configuration.
func (lc *LightChain) Config() *params.ChainConfig { return lc.hc.Config() }
// LockChain locks the chain mutex for reading so that multiple canonical hashes can be
// retrieved while it is guaranteed that they belong to the same version of the chain
func (lc *LightChain) LockChain() {
lc.chainmu.RLock()
}
// UnlockChain unlocks the chain mutex
func (lc *LightChain) UnlockChain() {
lc.chainmu.RUnlock()
}
// SubscribeChainEvent registers a subscription of ChainEvent.
func (lc *LightChain) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
return lc.scope.Track(lc.chainFeed.Subscribe(ch))
}
// SubscribeChainHeadEvent registers a subscription of ChainHeadEvent.
func (lc *LightChain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
return lc.scope.Track(lc.chainHeadFeed.Subscribe(ch))
}
// SubscribeChainSideEvent registers a subscription of ChainSideEvent.
func (lc *LightChain) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
return lc.scope.Track(lc.chainSideFeed.Subscribe(ch))
}
// SubscribeLogsEvent implements the interface of filters.Backend
// LightChain does not send logs events, so return an empty subscription.
func (lc *LightChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
return lc.scope.Track(new(event.Feed).Subscribe(ch))
}
// SubscribeRemovedLogsEvent implements the interface of filters.Backend
// LightChain does not send core.RemovedLogsEvent, so return an empty subscription.
func (lc *LightChain) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
return lc.scope.Track(new(event.Feed).Subscribe(ch))
}

View file

@ -1,358 +0,0 @@
// Copyright 2016 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 light
import (
"context"
"errors"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
)
// So we can deterministically seed different blockchains
var (
canonicalSeed = 1
forkSeed = 2
)
// makeHeaderChain creates a deterministic chain of headers rooted at parent.
func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) []*types.Header {
blocks, _ := core.GenerateChain(params.TestChainConfig, types.NewBlockWithHeader(parent), ethash.NewFaker(), db, n, func(i int, b *core.BlockGen) {
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
})
headers := make([]*types.Header, len(blocks))
for i, block := range blocks {
headers[i] = block.Header()
}
return headers
}
// newCanonical creates a chain database, and injects a deterministic canonical
// chain. Depending on the full flag, if creates either a full block chain or a
// header only chain.
func newCanonical(n int) (ethdb.Database, *LightChain, error) {
db := rawdb.NewMemoryDatabase()
gspec := core.Genesis{Config: params.TestChainConfig}
genesis := gspec.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults))
blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker())
// Create and inject the requested chain
if n == 0 {
return db, blockchain, nil
}
// Header-only chain requested
headers := makeHeaderChain(genesis.Header(), n, db, canonicalSeed)
_, err := blockchain.InsertHeaderChain(headers)
return db, blockchain, err
}
// newTestLightChain creates a LightChain that doesn't validate anything.
func newTestLightChain() *LightChain {
db := rawdb.NewMemoryDatabase()
gspec := &core.Genesis{
Difficulty: big.NewInt(1),
Config: params.TestChainConfig,
}
gspec.MustCommit(db, trie.NewDatabase(db, trie.HashDefaults))
lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker())
if err != nil {
panic(err)
}
return lc
}
// Test fork of length N starting from block i
func testFork(t *testing.T, LightChain *LightChain, i, n int, comparator func(td1, td2 *big.Int)) {
// Copy old chain up to #i into a new db
db, LightChain2, err := newCanonical(i)
if err != nil {
t.Fatal("could not make new canonical in testFork", err)
}
// Assert the chains have the same header/block at #i
var hash1, hash2 common.Hash
hash1 = LightChain.GetHeaderByNumber(uint64(i)).Hash()
hash2 = LightChain2.GetHeaderByNumber(uint64(i)).Hash()
if hash1 != hash2 {
t.Errorf("chain content mismatch at %d: have hash %v, want hash %v", i, hash2, hash1)
}
// Extend the newly created chain
headerChainB := makeHeaderChain(LightChain2.CurrentHeader(), n, db, forkSeed)
if _, err := LightChain2.InsertHeaderChain(headerChainB); err != nil {
t.Fatalf("failed to insert forking chain: %v", err)
}
// Sanity check that the forked chain can be imported into the original
var tdPre, tdPost *big.Int
cur := LightChain.CurrentHeader()
tdPre = LightChain.GetTd(cur.Hash(), cur.Number.Uint64())
if err := testHeaderChainImport(headerChainB, LightChain); err != nil {
t.Fatalf("failed to import forked header chain: %v", err)
}
last := headerChainB[len(headerChainB)-1]
tdPost = LightChain.GetTd(last.Hash(), last.Number.Uint64())
// Compare the total difficulties of the chains
comparator(tdPre, tdPost)
}
// testHeaderChainImport tries to process a chain of header, writing them into
// the database if successful.
func testHeaderChainImport(chain []*types.Header, lightchain *LightChain) error {
for _, header := range chain {
// Try and validate the header
if err := lightchain.engine.VerifyHeader(lightchain.hc, header); err != nil {
return err
}
// Manually insert the header into the database, but don't reorganize (allows subsequent testing)
lightchain.chainmu.Lock()
rawdb.WriteTd(lightchain.chainDb, header.Hash(), header.Number.Uint64(),
new(big.Int).Add(header.Difficulty, lightchain.GetTd(header.ParentHash, header.Number.Uint64()-1)))
rawdb.WriteHeader(lightchain.chainDb, header)
lightchain.chainmu.Unlock()
}
return nil
}
// Tests that given a starting canonical chain of a given size, it can be extended
// with various length chains.
func TestExtendCanonicalHeaders(t *testing.T) {
length := 5
// Make first chain starting from genesis
_, processor, err := newCanonical(length)
if err != nil {
t.Fatalf("failed to make new canonical chain: %v", err)
}
// Define the difficulty comparator
better := func(td1, td2 *big.Int) {
if td2.Cmp(td1) <= 0 {
t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1)
}
}
// Start fork from current height
testFork(t, processor, length, 1, better)
testFork(t, processor, length, 2, better)
testFork(t, processor, length, 5, better)
testFork(t, processor, length, 10, better)
}
// Tests that given a starting canonical chain of a given size, creating shorter
// forks do not take canonical ownership.
func TestShorterForkHeaders(t *testing.T) {
length := 10
// Make first chain starting from genesis
_, processor, err := newCanonical(length)
if err != nil {
t.Fatalf("failed to make new canonical chain: %v", err)
}
// Define the difficulty comparator
worse := func(td1, td2 *big.Int) {
if td2.Cmp(td1) >= 0 {
t.Errorf("total difficulty mismatch: have %v, expected less than %v", td2, td1)
}
}
// Sum of numbers must be less than `length` for this to be a shorter fork
testFork(t, processor, 0, 3, worse)
testFork(t, processor, 0, 7, worse)
testFork(t, processor, 1, 1, worse)
testFork(t, processor, 1, 7, worse)
testFork(t, processor, 5, 3, worse)
testFork(t, processor, 5, 4, worse)
}
// Tests that given a starting canonical chain of a given size, creating longer
// forks do take canonical ownership.
func TestLongerForkHeaders(t *testing.T) {
length := 10
// Make first chain starting from genesis
_, processor, err := newCanonical(length)
if err != nil {
t.Fatalf("failed to make new canonical chain: %v", err)
}
// Define the difficulty comparator
better := func(td1, td2 *big.Int) {
if td2.Cmp(td1) <= 0 {
t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1)
}
}
// Sum of numbers must be greater than `length` for this to be a longer fork
testFork(t, processor, 0, 11, better)
testFork(t, processor, 0, 15, better)
testFork(t, processor, 1, 10, better)
testFork(t, processor, 1, 12, better)
testFork(t, processor, 5, 6, better)
testFork(t, processor, 5, 8, better)
}
// Tests that given a starting canonical chain of a given size, creating equal
// forks do take canonical ownership.
func TestEqualForkHeaders(t *testing.T) {
length := 10
// Make first chain starting from genesis
_, processor, err := newCanonical(length)
if err != nil {
t.Fatalf("failed to make new canonical chain: %v", err)
}
// Define the difficulty comparator
equal := func(td1, td2 *big.Int) {
if td2.Cmp(td1) != 0 {
t.Errorf("total difficulty mismatch: have %v, want %v", td2, td1)
}
}
// Sum of numbers must be equal to `length` for this to be an equal fork
testFork(t, processor, 0, 10, equal)
testFork(t, processor, 1, 9, equal)
testFork(t, processor, 2, 8, equal)
testFork(t, processor, 5, 5, equal)
testFork(t, processor, 6, 4, equal)
testFork(t, processor, 9, 1, equal)
}
// Tests that chains missing links do not get accepted by the processor.
func TestBrokenHeaderChain(t *testing.T) {
// Make chain starting from genesis
db, LightChain, err := newCanonical(10)
if err != nil {
t.Fatalf("failed to make new canonical chain: %v", err)
}
// Create a forked chain, and try to insert with a missing link
chain := makeHeaderChain(LightChain.CurrentHeader(), 5, db, forkSeed)[1:]
if err := testHeaderChainImport(chain, LightChain); err == nil {
t.Errorf("broken header chain not reported")
}
}
func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header {
var chain []*types.Header
for i, difficulty := range d {
header := &types.Header{
Coinbase: common.Address{seed},
Number: big.NewInt(int64(i + 1)),
Difficulty: big.NewInt(int64(difficulty)),
UncleHash: types.EmptyUncleHash,
TxHash: types.EmptyTxsHash,
ReceiptHash: types.EmptyReceiptsHash,
}
if i == 0 {
header.ParentHash = genesis.Hash()
} else {
header.ParentHash = chain[i-1].Hash()
}
chain = append(chain, types.CopyHeader(header))
}
return chain
}
type dummyOdr struct {
OdrBackend
db ethdb.Database
indexerConfig *IndexerConfig
}
func (odr *dummyOdr) Database() ethdb.Database {
return odr.db
}
func (odr *dummyOdr) Retrieve(ctx context.Context, req OdrRequest) error {
return nil
}
func (odr *dummyOdr) IndexerConfig() *IndexerConfig {
return odr.indexerConfig
}
// Tests that reorganizing a long difficult chain after a short easy one
// overwrites the canonical numbers and links in the database.
func TestReorgLongHeaders(t *testing.T) {
testReorg(t, []int{1, 2, 4}, []int{1, 2, 3, 4}, 10)
}
// Tests that reorganizing a short difficult chain after a long easy one
// overwrites the canonical numbers and links in the database.
func TestReorgShortHeaders(t *testing.T) {
testReorg(t, []int{1, 2, 3, 4}, []int{1, 10}, 11)
}
func testReorg(t *testing.T, first, second []int, td int64) {
bc := newTestLightChain()
// Insert an easy and a difficult chain afterwards
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11))
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22))
// Check that the chain is valid number and link wise
prev := bc.CurrentHeader()
for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) {
if prev.ParentHash != header.Hash() {
t.Errorf("parent header hash mismatch: have %x, want %x", prev.ParentHash, header.Hash())
}
}
// Make sure the chain total difficulty is the correct one
want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td))
if have := bc.GetTd(bc.CurrentHeader().Hash(), bc.CurrentHeader().Number.Uint64()); have.Cmp(want) != 0 {
t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
}
}
// Tests that the insertion functions detect banned hashes.
func TestBadHeaderHashes(t *testing.T) {
bc := newTestLightChain()
// Create a chain, ban a hash and try to import
var err error
headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
core.BadHashes[headers[2].Hash()] = true
if _, err = bc.InsertHeaderChain(headers); !errors.Is(err, core.ErrBannedHash) {
t.Errorf("error mismatch: have: %v, want %v", err, core.ErrBannedHash)
}
}
// Tests that bad hashes are detected on boot, and the chan rolled back to a
// good state prior to the bad hash.
func TestReorgBadHeaderHashes(t *testing.T) {
bc := newTestLightChain()
// Create a chain, import and ban afterwards
headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
if _, err := bc.InsertHeaderChain(headers); err != nil {
t.Fatalf("failed to import headers: %v", err)
}
if bc.CurrentHeader().Hash() != headers[3].Hash() {
t.Errorf("last header hash mismatch: have: %x, want %x", bc.CurrentHeader().Hash(), headers[3].Hash())
}
core.BadHashes[headers[3].Hash()] = true
defer func() { delete(core.BadHashes, headers[3].Hash()) }()
// Create a new LightChain and check that it rolled back the state.
ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker())
if err != nil {
t.Fatalf("failed to create new chain manager: %v", err)
}
if ncm.CurrentHeader().Hash() != headers[2].Hash() {
t.Errorf("last header hash mismatch: have: %x, want %x", ncm.CurrentHeader().Hash(), headers[2].Hash())
}
}

View file

@ -1,196 +0,0 @@
// Copyright 2015 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 light
import (
"context"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/trie/trienode"
)
// NoOdr is the default context passed to an ODR capable function when the ODR
// service is not required.
var NoOdr = context.Background()
// ErrNoPeers is returned if no peers capable of serving a queued request are available
var ErrNoPeers = errors.New("no suitable peers available")
// OdrBackend is an interface to a backend service that handles ODR retrievals type
type OdrBackend interface {
Database() ethdb.Database
ChtIndexer() *core.ChainIndexer
BloomTrieIndexer() *core.ChainIndexer
BloomIndexer() *core.ChainIndexer
Retrieve(ctx context.Context, req OdrRequest) error
RetrieveTxStatus(ctx context.Context, req *TxStatusRequest) error
IndexerConfig() *IndexerConfig
}
// OdrRequest is an interface for retrieval requests
type OdrRequest interface {
StoreResult(db ethdb.Database)
}
// TrieID identifies a state or account storage trie
type TrieID struct {
BlockHash common.Hash
BlockNumber uint64
StateRoot common.Hash
Root common.Hash
AccountAddress []byte
}
// StateTrieID returns a TrieID for a state trie belonging to a certain block
// header.
func StateTrieID(header *types.Header) *TrieID {
return &TrieID{
BlockHash: header.Hash(),
BlockNumber: header.Number.Uint64(),
StateRoot: header.Root,
Root: header.Root,
AccountAddress: nil,
}
}
// StorageTrieID returns a TrieID for a contract storage trie at a given account
// of a given state trie. It also requires the root hash of the trie for
// checking Merkle proofs.
func StorageTrieID(state *TrieID, address common.Address, root common.Hash) *TrieID {
return &TrieID{
BlockHash: state.BlockHash,
BlockNumber: state.BlockNumber,
StateRoot: state.StateRoot,
AccountAddress: address[:],
Root: root,
}
}
// TrieRequest is the ODR request type for state/storage trie entries
type TrieRequest struct {
Id *TrieID
Key []byte
Proof *trienode.ProofSet
}
// StoreResult stores the retrieved data in local database
func (req *TrieRequest) StoreResult(db ethdb.Database) {
req.Proof.Store(db)
}
// CodeRequest is the ODR request type for retrieving contract code
type CodeRequest struct {
Id *TrieID // references storage trie of the account
Hash common.Hash
Data []byte
}
// StoreResult stores the retrieved data in local database
func (req *CodeRequest) StoreResult(db ethdb.Database) {
rawdb.WriteCode(db, req.Hash, req.Data)
}
// BlockRequest is the ODR request type for retrieving block bodies
type BlockRequest struct {
Hash common.Hash
Number uint64
Header *types.Header
Rlp []byte
}
// StoreResult stores the retrieved data in local database
func (req *BlockRequest) StoreResult(db ethdb.Database) {
rawdb.WriteBodyRLP(db, req.Hash, req.Number, req.Rlp)
}
// ReceiptsRequest is the ODR request type for retrieving receipts.
type ReceiptsRequest struct {
Hash common.Hash
Number uint64
Header *types.Header
Receipts types.Receipts
}
// StoreResult stores the retrieved data in local database
func (req *ReceiptsRequest) StoreResult(db ethdb.Database) {
rawdb.WriteReceipts(db, req.Hash, req.Number, req.Receipts)
}
// ChtRequest is the ODR request type for retrieving header by Canonical Hash Trie
type ChtRequest struct {
Config *IndexerConfig
ChtNum, BlockNum uint64
ChtRoot common.Hash
Header *types.Header
Td *big.Int
Proof *trienode.ProofSet
}
// StoreResult stores the retrieved data in local database
func (req *ChtRequest) StoreResult(db ethdb.Database) {
hash, num := req.Header.Hash(), req.Header.Number.Uint64()
rawdb.WriteHeader(db, req.Header)
rawdb.WriteTd(db, hash, num, req.Td)
rawdb.WriteCanonicalHash(db, hash, num)
}
// BloomRequest is the ODR request type for retrieving bloom filters from a CHT structure
type BloomRequest struct {
OdrRequest
Config *IndexerConfig
BloomTrieNum uint64
BitIdx uint
SectionIndexList []uint64
BloomTrieRoot common.Hash
BloomBits [][]byte
Proofs *trienode.ProofSet
}
// StoreResult stores the retrieved data in local database
func (req *BloomRequest) StoreResult(db ethdb.Database) {
for i, sectionIdx := range req.SectionIndexList {
sectionHead := rawdb.ReadCanonicalHash(db, (sectionIdx+1)*req.Config.BloomTrieSize-1)
// if we don't have the canonical hash stored for this section head number, we'll still store it under
// a key with a zero sectionHead. GetBloomBits will look there too if we still don't have the canonical
// hash. In the unlikely case we've retrieved the section head hash since then, we'll just retrieve the
// bit vector again from the network.
rawdb.WriteBloomBits(db, req.BitIdx, sectionIdx, sectionHead, req.BloomBits[i])
}
}
// TxStatus describes the status of a transaction
type TxStatus struct {
Status txpool.TxStatus
Lookup *rawdb.LegacyTxLookupEntry `rlp:"nil"`
Error string
}
// TxStatusRequest is the ODR request type for retrieving transaction status
type TxStatusRequest struct {
Hashes []common.Hash
Status []TxStatus
}
// StoreResult stores the retrieved data in local database
func (req *TxStatusRequest) StoreResult(db ethdb.Database) {}

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