mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 09:23:48 +00:00
Merge branch 'extended-tracer' into firehose-fh3.0
# Conflicts: # go.mod # go.sum
This commit is contained in:
commit
306a1fca64
137 changed files with 2313 additions and 5774 deletions
23
.github/workflows/go.yml
vendored
Normal file
23
.github/workflows/go.yml
vendored
Normal 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
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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"))
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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":"----"}]}]}]`))
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"`
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
if tracer != nil {
|
||||||
tracer.CaptureTxStart(evm, tx, msg.From)
|
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)
|
||||||
|
if tracer != nil {
|
||||||
tracer.CaptureTxEnd(nil, err)
|
tracer.CaptureTxEnd(nil, err)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
includedTxs = append(includedTxs, tx)
|
includedTxs = append(includedTxs, tx)
|
||||||
|
|
@ -284,8 +288,10 @@ 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)
|
||||||
|
if tracer != nil {
|
||||||
tracer.CaptureTxEnd(receipt, 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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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{
|
||||||
|
|
|
||||||
|
|
@ -584,7 +584,7 @@ func dumpState(ctx *cli.Context) error {
|
||||||
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))
|
||||||
|
|
|
||||||
101
cmd/geth/testdata/logging/logtest-json.txt
vendored
101
cmd/geth/testdata/logging/logtest-json.txt
vendored
|
|
@ -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"}
|
||||||
|
|
|
||||||
103
cmd/geth/testdata/logging/logtest-logfmt.txt
vendored
103
cmd/geth/testdata/logging/logtest-logfmt.txt
vendored
|
|
@ -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"
|
||||||
|
|
|
||||||
103
cmd/geth/testdata/logging/logtest-terminal.txt
vendored
103
cmd/geth/testdata/logging/logtest-terminal.txt
vendored
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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++ {
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}()
|
}()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -56,14 +56,17 @@ type DumpAccount struct {
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,7 +98,7 @@ func (d iterativeDump) OnAccount(addr *common.Address, account DumpAccount) {
|
||||||
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{
|
var (
|
||||||
|
account = DumpAccount{
|
||||||
Balance: data.Balance.String(),
|
Balance: data.Balance.String(),
|
||||||
Nonce: data.Nonce,
|
Nonce: data.Nonce,
|
||||||
Root: data.Root[:],
|
Root: data.Root[:],
|
||||||
CodeHash: data.CodeHash,
|
CodeHash: data.CodeHash,
|
||||||
SecureKey: it.Key,
|
AddressHash: it.Key,
|
||||||
}
|
}
|
||||||
var (
|
|
||||||
addrBytes = s.trie.GetKey(it.Key)
|
|
||||||
addr = common.BytesToAddress(addrBytes)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,8 @@ 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
|
||||||
|
RefundedGas uint64 // Total gas refunded after execution
|
||||||
Err error // Any error encountered during the execution(listed in core/vm/errors.go)
|
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)
|
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
|
||||||
}
|
}
|
||||||
|
|
@ -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(),
|
||||||
|
RefundedGas: gasRefund,
|
||||||
Err: vmerr,
|
Err: vmerr,
|
||||||
ReturnData: ret,
|
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.
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
235
eth/gasestimator/gasestimator.go
Normal file
235
eth/gasestimator/gasestimator.go
Normal 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
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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,19 +1174,19 @@ 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,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@
|
||||||
},
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"0x808b4da0be6c9512e948521452227efc619bea52": {
|
"0x808b4da0be6c9512e948521452227efc619bea52": {
|
||||||
"balance": "0x2cd72a36dd031f089",
|
"balance": "0x2cd987071ba2346b6",
|
||||||
"nonce": 1223933
|
"nonce": 1223933
|
||||||
},
|
},
|
||||||
"0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": {
|
"0x8f03f1a3f10c05e7cccf75c1fd10168e06659be7": {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
21
go.mod
|
|
@ -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
42
go.sum
|
|
@ -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=
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
@ -181,44 +169,33 @@ 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)
|
||||||
|
output io.Writer
|
||||||
logFmtFlag = ctx.String(logFormatFlag.Name)
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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())
|
// Run the gas estimation andwrap any revertals into a custom return
|
||||||
}
|
call, err := args.ToMessage(gasCap, header.BaseFee)
|
||||||
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.
|
|
||||||
if gasCap != 0 && hi > gasCap {
|
|
||||||
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 len(result.Revert()) > 0 {
|
|
||||||
return 0, newRevertError(result)
|
|
||||||
}
|
|
||||||
return 0, result.Err
|
|
||||||
}
|
|
||||||
return 0, 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 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 {
|
if err != nil {
|
||||||
// This should not happen under normal conditions since if we make it this far the
|
if len(revert) > 0 {
|
||||||
// transaction had run without error at least once before.
|
return 0, newRevertError(revert)
|
||||||
log.Error("execution error in estimate gas", "err", err)
|
}
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if failed {
|
return hexutil.Uint64(estimate), nil
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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))
|
|
||||||
}
|
|
||||||
|
|
@ -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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
196
light/odr.go
196
light/odr.go
|
|
@ -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
Loading…
Reference in a new issue