mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
resolve merge conflict
This commit is contained in:
commit
102aa8017a
144 changed files with 7274 additions and 4424 deletions
6
.github/CODEOWNERS
vendored
6
.github/CODEOWNERS
vendored
|
|
@ -4,14 +4,18 @@
|
|||
accounts/usbwallet @karalabe
|
||||
accounts/scwallet @gballet
|
||||
accounts/abi @gballet @MariusVanDerWijden
|
||||
beacon/engine @lightclient
|
||||
cmd/clef @holiman
|
||||
cmd/evm @holiman @MariusVanDerWijden @lightclient
|
||||
consensus @karalabe
|
||||
core/ @karalabe @holiman @rjl493456442
|
||||
eth/ @karalabe @holiman @rjl493456442
|
||||
eth/catalyst/ @gballet
|
||||
eth/catalyst/ @gballet @lightclient
|
||||
eth/tracers/ @s1na
|
||||
core/tracing/ @s1na
|
||||
graphql/ @s1na
|
||||
internal/ethapi @lightclient
|
||||
internal/era @lightclient
|
||||
les/ @zsfelfoldi @rjl493456442
|
||||
light/ @zsfelfoldi @rjl493456442
|
||||
node/ @fjl
|
||||
|
|
|
|||
1
.github/workflows/go.yml
vendored
1
.github/workflows/go.yml
vendored
|
|
@ -16,6 +16,7 @@ jobs:
|
|||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.21.4
|
||||
cache: false
|
||||
- name: Run tests
|
||||
run: go test -short ./...
|
||||
env:
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ linters:
|
|||
- durationcheck
|
||||
- exportloopref
|
||||
- whitespace
|
||||
- revive # only certain checks enabled
|
||||
|
||||
### linters we tried and will not be using:
|
||||
###
|
||||
|
|
@ -38,6 +39,15 @@ linters:
|
|||
linters-settings:
|
||||
gofmt:
|
||||
simplify: true
|
||||
revive:
|
||||
enable-all-rules: false
|
||||
# here we enable specific useful rules
|
||||
# see https://golangci-lint.run/usage/linters/#revive for supported rules
|
||||
rules:
|
||||
- name: receiver-naming
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
|
||||
issues:
|
||||
exclude-files:
|
||||
|
|
@ -47,6 +57,9 @@ issues:
|
|||
linters:
|
||||
- deadcode
|
||||
- staticcheck
|
||||
- path: crypto/bn256/
|
||||
linters:
|
||||
- revive
|
||||
- path: internal/build/pgp.go
|
||||
text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
|
||||
- path: core/vm/contracts.go
|
||||
|
|
|
|||
|
|
@ -171,5 +171,5 @@ i4O1UeWKs9owWttan9+PI47ozBSKOTxmMqLSQ0f56Np9FJsV0ilGxRKfjhzJ4KniOMUBA7mP
|
|||
epy6lH7HmxjjOR7eo0DaSxQGQpThAtFGwkWkFh8yki8j3E42kkrxvEyyYZDXn2YcI3bpqhJx
|
||||
PtwCMZUJ3kc/skOrs6bOI19iBNaEoNX5Dllm7UHjOgWNDQkcCuOCxucKano=
|
||||
=arte
|
||||
-----END PGP PUBLIC KEY BLOCK------
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
```
|
||||
|
|
|
|||
487
accounts/abi/bind/source.go.tpl
Normal file
487
accounts/abi/bind/source.go.tpl
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
// Code generated - DO NOT EDIT.
|
||||
// This file is a generated binding and any manual changes will be lost.
|
||||
|
||||
package {{.Package}}
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"strings"
|
||||
"errors"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var (
|
||||
_ = errors.New
|
||||
_ = big.NewInt
|
||||
_ = strings.NewReader
|
||||
_ = ethereum.NotFound
|
||||
_ = bind.Bind
|
||||
_ = common.Big1
|
||||
_ = types.BloomLookup
|
||||
_ = event.NewSubscription
|
||||
_ = abi.ConvertType
|
||||
)
|
||||
|
||||
{{$structs := .Structs}}
|
||||
{{range $structs}}
|
||||
// {{.Name}} is an auto generated low-level Go binding around an user-defined struct.
|
||||
type {{.Name}} struct {
|
||||
{{range $field := .Fields}}
|
||||
{{$field.Name}} {{$field.Type}}{{end}}
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range $contract := .Contracts}}
|
||||
// {{.Type}}MetaData contains all meta data concerning the {{.Type}} contract.
|
||||
var {{.Type}}MetaData = &bind.MetaData{
|
||||
ABI: "{{.InputABI}}",
|
||||
{{if $contract.FuncSigs -}}
|
||||
Sigs: map[string]string{
|
||||
{{range $strsig, $binsig := .FuncSigs}}"{{$binsig}}": "{{$strsig}}",
|
||||
{{end}}
|
||||
},
|
||||
{{end -}}
|
||||
{{if .InputBin -}}
|
||||
Bin: "0x{{.InputBin}}",
|
||||
{{end}}
|
||||
}
|
||||
// {{.Type}}ABI is the input ABI used to generate the binding from.
|
||||
// Deprecated: Use {{.Type}}MetaData.ABI instead.
|
||||
var {{.Type}}ABI = {{.Type}}MetaData.ABI
|
||||
|
||||
{{if $contract.FuncSigs}}
|
||||
// Deprecated: Use {{.Type}}MetaData.Sigs instead.
|
||||
// {{.Type}}FuncSigs maps the 4-byte function signature to its string representation.
|
||||
var {{.Type}}FuncSigs = {{.Type}}MetaData.Sigs
|
||||
{{end}}
|
||||
|
||||
{{if .InputBin}}
|
||||
// {{.Type}}Bin is the compiled bytecode used for deploying new contracts.
|
||||
// Deprecated: Use {{.Type}}MetaData.Bin instead.
|
||||
var {{.Type}}Bin = {{.Type}}MetaData.Bin
|
||||
|
||||
// Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it.
|
||||
func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type $structs}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) {
|
||||
parsed, err := {{.Type}}MetaData.GetAbi()
|
||||
if err != nil {
|
||||
return common.Address{}, nil, nil, err
|
||||
}
|
||||
if parsed == nil {
|
||||
return common.Address{}, nil, nil, errors.New("GetABI returned nil")
|
||||
}
|
||||
{{range $pattern, $name := .Libraries}}
|
||||
{{decapitalise $name}}Addr, _, _, _ := Deploy{{capitalise $name}}(auth, backend)
|
||||
{{$contract.Type}}Bin = strings.ReplaceAll({{$contract.Type}}Bin, "__${{$pattern}}$__", {{decapitalise $name}}Addr.String()[2:])
|
||||
{{end}}
|
||||
address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex({{.Type}}Bin), backend {{range .Constructor.Inputs}}, {{.Name}}{{end}})
|
||||
if err != nil {
|
||||
return common.Address{}, nil, nil, err
|
||||
}
|
||||
return address, tx, &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil
|
||||
}
|
||||
{{end}}
|
||||
|
||||
// {{.Type}} is an auto generated Go binding around an Ethereum contract.
|
||||
type {{.Type}} struct {
|
||||
{{.Type}}Caller // Read-only binding to the contract
|
||||
{{.Type}}Transactor // Write-only binding to the contract
|
||||
{{.Type}}Filterer // Log filterer for contract events
|
||||
}
|
||||
|
||||
// {{.Type}}Caller is an auto generated read-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}Caller struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// {{.Type}}Transactor is an auto generated write-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}Transactor struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// {{.Type}}Filterer is an auto generated log filtering Go binding around an Ethereum contract events.
|
||||
type {{.Type}}Filterer struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// {{.Type}}Session is an auto generated Go binding around an Ethereum contract,
|
||||
// with pre-set call and transact options.
|
||||
type {{.Type}}Session struct {
|
||||
Contract *{{.Type}} // Generic contract binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// {{.Type}}CallerSession is an auto generated read-only Go binding around an Ethereum contract,
|
||||
// with pre-set call options.
|
||||
type {{.Type}}CallerSession struct {
|
||||
Contract *{{.Type}}Caller // Generic contract caller binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
}
|
||||
|
||||
// {{.Type}}TransactorSession is an auto generated write-only Go binding around an Ethereum contract,
|
||||
// with pre-set transact options.
|
||||
type {{.Type}}TransactorSession struct {
|
||||
Contract *{{.Type}}Transactor // Generic contract transactor binding to set the session for
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// {{.Type}}Raw is an auto generated low-level Go binding around an Ethereum contract.
|
||||
type {{.Type}}Raw struct {
|
||||
Contract *{{.Type}} // Generic contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// {{.Type}}CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}CallerRaw struct {
|
||||
Contract *{{.Type}}Caller // Generic read-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// {{.Type}}TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}TransactorRaw struct {
|
||||
Contract *{{.Type}}Transactor // Generic write-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// New{{.Type}} creates a new instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}(address common.Address, backend bind.ContractBackend) (*{{.Type}}, error) {
|
||||
contract, err := bind{{.Type}}(address, backend, backend, backend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil
|
||||
}
|
||||
|
||||
// New{{.Type}}Caller creates a new read-only instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}Caller(address common.Address, caller bind.ContractCaller) (*{{.Type}}Caller, error) {
|
||||
contract, err := bind{{.Type}}(address, caller, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}Caller{contract: contract}, nil
|
||||
}
|
||||
|
||||
// New{{.Type}}Transactor creates a new write-only instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}Transactor(address common.Address, transactor bind.ContractTransactor) (*{{.Type}}Transactor, error) {
|
||||
contract, err := bind{{.Type}}(address, nil, transactor, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}Transactor{contract: contract}, nil
|
||||
}
|
||||
|
||||
// New{{.Type}}Filterer creates a new log filterer instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}Filterer(address common.Address, filterer bind.ContractFilterer) (*{{.Type}}Filterer, error) {
|
||||
contract, err := bind{{.Type}}(address, nil, nil, filterer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}Filterer{contract: contract}, nil
|
||||
}
|
||||
|
||||
// bind{{.Type}} binds a generic wrapper to an already deployed contract.
|
||||
func bind{{.Type}}(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
|
||||
parsed, err := {{.Type}}MetaData.GetAbi()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _{{$contract.Type}}.Contract.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
{{range .Calls}}
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) {
|
||||
var out []interface{}
|
||||
err := _{{$contract.Type}}.contract.Call(opts, &out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
{{if .Structured}}
|
||||
outstruct := new(struct{ {{range .Normalized.Outputs}} {{.Name}} {{bindtype .Type $structs}}; {{end}} })
|
||||
if err != nil {
|
||||
return *outstruct, err
|
||||
}
|
||||
{{range $i, $t := .Normalized.Outputs}}
|
||||
outstruct.{{.Name}} = *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}}
|
||||
|
||||
return *outstruct, err
|
||||
{{else}}
|
||||
if err != nil {
|
||||
return {{range $i, $_ := .Normalized.Outputs}}*new({{bindtype .Type $structs}}), {{end}} err
|
||||
}
|
||||
{{range $i, $t := .Normalized.Outputs}}
|
||||
out{{$i}} := *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}}
|
||||
|
||||
return {{range $i, $t := .Normalized.Outputs}}out{{$i}}, {{end}} err
|
||||
{{end}}
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range .Transacts}}
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) {{.Normalized.Name}}(opts *bind.TransactOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.Transact(opts, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{if .Fallback}}
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: {{.Fallback.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.RawTransact(opts, calldata)
|
||||
}
|
||||
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: {{.Fallback.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) Fallback(calldata []byte) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata)
|
||||
}
|
||||
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: {{.Fallback.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Fallback(calldata []byte) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata)
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{if .Receive}}
|
||||
// Receive is a paid mutator transaction binding the contract receive function.
|
||||
//
|
||||
// Solidity: {{.Receive.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.RawTransact(opts, nil) // calldata is disallowed for receive function
|
||||
}
|
||||
|
||||
// Receive is a paid mutator transaction binding the contract receive function.
|
||||
//
|
||||
// Solidity: {{.Receive.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) Receive() (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts)
|
||||
}
|
||||
|
||||
// Receive is a paid mutator transaction binding the contract receive function.
|
||||
//
|
||||
// Solidity: {{.Receive.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Receive() (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts)
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range .Events}}
|
||||
// {{$contract.Type}}{{.Normalized.Name}}Iterator is returned from Filter{{.Normalized.Name}} and is used to iterate over the raw logs and unpacked data for {{.Normalized.Name}} events raised by the {{$contract.Type}} contract.
|
||||
type {{$contract.Type}}{{.Normalized.Name}}Iterator struct {
|
||||
Event *{{$contract.Type}}{{.Normalized.Name}} // Event containing the contract specifics and raw log
|
||||
|
||||
contract *bind.BoundContract // Generic contract to use for unpacking event data
|
||||
event string // Event name to use for unpacking event data
|
||||
|
||||
logs chan types.Log // Log channel receiving the found contract events
|
||||
sub ethereum.Subscription // Subscription for errors, completion and termination
|
||||
done bool // Whether the subscription completed delivering logs
|
||||
fail error // Occurred error to stop iteration
|
||||
}
|
||||
// Next advances the iterator to the subsequent event, returning whether there
|
||||
// are any more events found. In case of a retrieval or parsing error, false is
|
||||
// returned and Error() can be queried for the exact failure.
|
||||
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Next() bool {
|
||||
// If the iterator failed, stop iterating
|
||||
if (it.fail != nil) {
|
||||
return false
|
||||
}
|
||||
// If the iterator completed, deliver directly whatever's available
|
||||
if (it.done) {
|
||||
select {
|
||||
case log := <-it.logs:
|
||||
it.Event = new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
|
||||
it.fail = err
|
||||
return false
|
||||
}
|
||||
it.Event.Raw = log
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
// Iterator still in progress, wait for either a data or an error event
|
||||
select {
|
||||
case log := <-it.logs:
|
||||
it.Event = new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
|
||||
it.fail = err
|
||||
return false
|
||||
}
|
||||
it.Event.Raw = log
|
||||
return true
|
||||
|
||||
case err := <-it.sub.Err():
|
||||
it.done = true
|
||||
it.fail = err
|
||||
return it.Next()
|
||||
}
|
||||
}
|
||||
// Error returns any retrieval or parsing error occurred during filtering.
|
||||
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Error() error {
|
||||
return it.fail
|
||||
}
|
||||
// Close terminates the iteration process, releasing any pending underlying
|
||||
// resources.
|
||||
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Close() error {
|
||||
it.sub.Unsubscribe()
|
||||
return nil
|
||||
}
|
||||
|
||||
// {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event raised by the {{$contract.Type}} contract.
|
||||
type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}}
|
||||
{{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type $structs}}{{else}}{{bindtype .Type $structs}}{{end}}; {{end}}
|
||||
Raw types.Log // Blockchain specific contextual infos
|
||||
}
|
||||
|
||||
// Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) {
|
||||
{{range .Normalized.Inputs}}
|
||||
{{if .Indexed}}var {{.Name}}Rule []interface{}
|
||||
for _, {{.Name}}Item := range {{.Name}} {
|
||||
{{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item)
|
||||
}{{end}}{{end}}
|
||||
|
||||
logs, sub, err := _{{$contract.Type}}.contract.FilterLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{$contract.Type}}{{.Normalized.Name}}Iterator{contract: _{{$contract.Type}}.contract, event: "{{.Original.Name}}", logs: logs, sub: sub}, nil
|
||||
}
|
||||
|
||||
// Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (event.Subscription, error) {
|
||||
{{range .Normalized.Inputs}}
|
||||
{{if .Indexed}}var {{.Name}}Rule []interface{}
|
||||
for _, {{.Name}}Item := range {{.Name}} {
|
||||
{{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item)
|
||||
}{{end}}{{end}}
|
||||
|
||||
logs, sub, err := _{{$contract.Type}}.contract.WatchLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return event.NewSubscription(func(quit <-chan struct{}) error {
|
||||
defer sub.Unsubscribe()
|
||||
for {
|
||||
select {
|
||||
case log := <-logs:
|
||||
// New log arrived, parse the event and forward to the user
|
||||
event := new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil {
|
||||
return err
|
||||
}
|
||||
event.Raw = log
|
||||
|
||||
select {
|
||||
case sink <- event:
|
||||
case err := <-sub.Err():
|
||||
return err
|
||||
case <-quit:
|
||||
return nil
|
||||
}
|
||||
case err := <-sub.Err():
|
||||
return err
|
||||
case <-quit:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}), nil
|
||||
}
|
||||
|
||||
// Parse{{.Normalized.Name}} is a log parse operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Parse{{.Normalized.Name}}(log types.Log) (*{{$contract.Type}}{{.Normalized.Name}}, error) {
|
||||
event := new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
event.Raw = log
|
||||
return event, nil
|
||||
}
|
||||
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
@ -16,7 +16,11 @@
|
|||
|
||||
package bind
|
||||
|
||||
import "github.com/ethereum/go-ethereum/accounts/abi"
|
||||
import (
|
||||
_ "embed"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
)
|
||||
|
||||
// tmplData is the data structure required to fill the binding template.
|
||||
type tmplData struct {
|
||||
|
|
@ -80,492 +84,6 @@ var tmplSource = map[Lang]string{
|
|||
|
||||
// tmplSourceGo is the Go source template that the generated Go contract binding
|
||||
// is based on.
|
||||
const tmplSourceGo = `
|
||||
// Code generated - DO NOT EDIT.
|
||||
// This file is a generated binding and any manual changes will be lost.
|
||||
|
||||
package {{.Package}}
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"strings"
|
||||
"errors"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var (
|
||||
_ = errors.New
|
||||
_ = big.NewInt
|
||||
_ = strings.NewReader
|
||||
_ = ethereum.NotFound
|
||||
_ = bind.Bind
|
||||
_ = common.Big1
|
||||
_ = types.BloomLookup
|
||||
_ = event.NewSubscription
|
||||
_ = abi.ConvertType
|
||||
)
|
||||
|
||||
{{$structs := .Structs}}
|
||||
{{range $structs}}
|
||||
// {{.Name}} is an auto generated low-level Go binding around an user-defined struct.
|
||||
type {{.Name}} struct {
|
||||
{{range $field := .Fields}}
|
||||
{{$field.Name}} {{$field.Type}}{{end}}
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range $contract := .Contracts}}
|
||||
// {{.Type}}MetaData contains all meta data concerning the {{.Type}} contract.
|
||||
var {{.Type}}MetaData = &bind.MetaData{
|
||||
ABI: "{{.InputABI}}",
|
||||
{{if $contract.FuncSigs -}}
|
||||
Sigs: map[string]string{
|
||||
{{range $strsig, $binsig := .FuncSigs}}"{{$binsig}}": "{{$strsig}}",
|
||||
{{end}}
|
||||
},
|
||||
{{end -}}
|
||||
{{if .InputBin -}}
|
||||
Bin: "0x{{.InputBin}}",
|
||||
{{end}}
|
||||
}
|
||||
// {{.Type}}ABI is the input ABI used to generate the binding from.
|
||||
// Deprecated: Use {{.Type}}MetaData.ABI instead.
|
||||
var {{.Type}}ABI = {{.Type}}MetaData.ABI
|
||||
|
||||
{{if $contract.FuncSigs}}
|
||||
// Deprecated: Use {{.Type}}MetaData.Sigs instead.
|
||||
// {{.Type}}FuncSigs maps the 4-byte function signature to its string representation.
|
||||
var {{.Type}}FuncSigs = {{.Type}}MetaData.Sigs
|
||||
{{end}}
|
||||
|
||||
{{if .InputBin}}
|
||||
// {{.Type}}Bin is the compiled bytecode used for deploying new contracts.
|
||||
// Deprecated: Use {{.Type}}MetaData.Bin instead.
|
||||
var {{.Type}}Bin = {{.Type}}MetaData.Bin
|
||||
|
||||
// Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it.
|
||||
func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type $structs}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) {
|
||||
parsed, err := {{.Type}}MetaData.GetAbi()
|
||||
if err != nil {
|
||||
return common.Address{}, nil, nil, err
|
||||
}
|
||||
if parsed == nil {
|
||||
return common.Address{}, nil, nil, errors.New("GetABI returned nil")
|
||||
}
|
||||
{{range $pattern, $name := .Libraries}}
|
||||
{{decapitalise $name}}Addr, _, _, _ := Deploy{{capitalise $name}}(auth, backend)
|
||||
{{$contract.Type}}Bin = strings.ReplaceAll({{$contract.Type}}Bin, "__${{$pattern}}$__", {{decapitalise $name}}Addr.String()[2:])
|
||||
{{end}}
|
||||
address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex({{.Type}}Bin), backend {{range .Constructor.Inputs}}, {{.Name}}{{end}})
|
||||
if err != nil {
|
||||
return common.Address{}, nil, nil, err
|
||||
}
|
||||
return address, tx, &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil
|
||||
}
|
||||
{{end}}
|
||||
|
||||
// {{.Type}} is an auto generated Go binding around an Ethereum contract.
|
||||
type {{.Type}} struct {
|
||||
{{.Type}}Caller // Read-only binding to the contract
|
||||
{{.Type}}Transactor // Write-only binding to the contract
|
||||
{{.Type}}Filterer // Log filterer for contract events
|
||||
}
|
||||
|
||||
// {{.Type}}Caller is an auto generated read-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}Caller struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// {{.Type}}Transactor is an auto generated write-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}Transactor struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// {{.Type}}Filterer is an auto generated log filtering Go binding around an Ethereum contract events.
|
||||
type {{.Type}}Filterer struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// {{.Type}}Session is an auto generated Go binding around an Ethereum contract,
|
||||
// with pre-set call and transact options.
|
||||
type {{.Type}}Session struct {
|
||||
Contract *{{.Type}} // Generic contract binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// {{.Type}}CallerSession is an auto generated read-only Go binding around an Ethereum contract,
|
||||
// with pre-set call options.
|
||||
type {{.Type}}CallerSession struct {
|
||||
Contract *{{.Type}}Caller // Generic contract caller binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
}
|
||||
|
||||
// {{.Type}}TransactorSession is an auto generated write-only Go binding around an Ethereum contract,
|
||||
// with pre-set transact options.
|
||||
type {{.Type}}TransactorSession struct {
|
||||
Contract *{{.Type}}Transactor // Generic contract transactor binding to set the session for
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// {{.Type}}Raw is an auto generated low-level Go binding around an Ethereum contract.
|
||||
type {{.Type}}Raw struct {
|
||||
Contract *{{.Type}} // Generic contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// {{.Type}}CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}CallerRaw struct {
|
||||
Contract *{{.Type}}Caller // Generic read-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// {{.Type}}TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}TransactorRaw struct {
|
||||
Contract *{{.Type}}Transactor // Generic write-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// New{{.Type}} creates a new instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}(address common.Address, backend bind.ContractBackend) (*{{.Type}}, error) {
|
||||
contract, err := bind{{.Type}}(address, backend, backend, backend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil
|
||||
}
|
||||
|
||||
// New{{.Type}}Caller creates a new read-only instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}Caller(address common.Address, caller bind.ContractCaller) (*{{.Type}}Caller, error) {
|
||||
contract, err := bind{{.Type}}(address, caller, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}Caller{contract: contract}, nil
|
||||
}
|
||||
|
||||
// New{{.Type}}Transactor creates a new write-only instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}Transactor(address common.Address, transactor bind.ContractTransactor) (*{{.Type}}Transactor, error) {
|
||||
contract, err := bind{{.Type}}(address, nil, transactor, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}Transactor{contract: contract}, nil
|
||||
}
|
||||
|
||||
// New{{.Type}}Filterer creates a new log filterer instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}Filterer(address common.Address, filterer bind.ContractFilterer) (*{{.Type}}Filterer, error) {
|
||||
contract, err := bind{{.Type}}(address, nil, nil, filterer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}Filterer{contract: contract}, nil
|
||||
}
|
||||
|
||||
// bind{{.Type}} binds a generic wrapper to an already deployed contract.
|
||||
func bind{{.Type}}(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
|
||||
parsed, err := {{.Type}}MetaData.GetAbi()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _{{$contract.Type}}.Contract.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
{{range .Calls}}
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) {
|
||||
var out []interface{}
|
||||
err := _{{$contract.Type}}.contract.Call(opts, &out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
{{if .Structured}}
|
||||
outstruct := new(struct{ {{range .Normalized.Outputs}} {{.Name}} {{bindtype .Type $structs}}; {{end}} })
|
||||
if err != nil {
|
||||
return *outstruct, err
|
||||
}
|
||||
{{range $i, $t := .Normalized.Outputs}}
|
||||
outstruct.{{.Name}} = *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}}
|
||||
|
||||
return *outstruct, err
|
||||
{{else}}
|
||||
if err != nil {
|
||||
return {{range $i, $_ := .Normalized.Outputs}}*new({{bindtype .Type $structs}}), {{end}} err
|
||||
}
|
||||
{{range $i, $t := .Normalized.Outputs}}
|
||||
out{{$i}} := *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}}
|
||||
|
||||
return {{range $i, $t := .Normalized.Outputs}}out{{$i}}, {{end}} err
|
||||
{{end}}
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range .Transacts}}
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) {{.Normalized.Name}}(opts *bind.TransactOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.Transact(opts, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{if .Fallback}}
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: {{.Fallback.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.RawTransact(opts, calldata)
|
||||
}
|
||||
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: {{.Fallback.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) Fallback(calldata []byte) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata)
|
||||
}
|
||||
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: {{.Fallback.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Fallback(calldata []byte) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata)
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{if .Receive}}
|
||||
// Receive is a paid mutator transaction binding the contract receive function.
|
||||
//
|
||||
// Solidity: {{.Receive.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.RawTransact(opts, nil) // calldata is disallowed for receive function
|
||||
}
|
||||
|
||||
// Receive is a paid mutator transaction binding the contract receive function.
|
||||
//
|
||||
// Solidity: {{.Receive.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) Receive() (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts)
|
||||
}
|
||||
|
||||
// Receive is a paid mutator transaction binding the contract receive function.
|
||||
//
|
||||
// Solidity: {{.Receive.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Receive() (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts)
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range .Events}}
|
||||
// {{$contract.Type}}{{.Normalized.Name}}Iterator is returned from Filter{{.Normalized.Name}} and is used to iterate over the raw logs and unpacked data for {{.Normalized.Name}} events raised by the {{$contract.Type}} contract.
|
||||
type {{$contract.Type}}{{.Normalized.Name}}Iterator struct {
|
||||
Event *{{$contract.Type}}{{.Normalized.Name}} // Event containing the contract specifics and raw log
|
||||
|
||||
contract *bind.BoundContract // Generic contract to use for unpacking event data
|
||||
event string // Event name to use for unpacking event data
|
||||
|
||||
logs chan types.Log // Log channel receiving the found contract events
|
||||
sub ethereum.Subscription // Subscription for errors, completion and termination
|
||||
done bool // Whether the subscription completed delivering logs
|
||||
fail error // Occurred error to stop iteration
|
||||
}
|
||||
// Next advances the iterator to the subsequent event, returning whether there
|
||||
// are any more events found. In case of a retrieval or parsing error, false is
|
||||
// returned and Error() can be queried for the exact failure.
|
||||
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Next() bool {
|
||||
// If the iterator failed, stop iterating
|
||||
if (it.fail != nil) {
|
||||
return false
|
||||
}
|
||||
// If the iterator completed, deliver directly whatever's available
|
||||
if (it.done) {
|
||||
select {
|
||||
case log := <-it.logs:
|
||||
it.Event = new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
|
||||
it.fail = err
|
||||
return false
|
||||
}
|
||||
it.Event.Raw = log
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
// Iterator still in progress, wait for either a data or an error event
|
||||
select {
|
||||
case log := <-it.logs:
|
||||
it.Event = new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
|
||||
it.fail = err
|
||||
return false
|
||||
}
|
||||
it.Event.Raw = log
|
||||
return true
|
||||
|
||||
case err := <-it.sub.Err():
|
||||
it.done = true
|
||||
it.fail = err
|
||||
return it.Next()
|
||||
}
|
||||
}
|
||||
// Error returns any retrieval or parsing error occurred during filtering.
|
||||
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Error() error {
|
||||
return it.fail
|
||||
}
|
||||
// Close terminates the iteration process, releasing any pending underlying
|
||||
// resources.
|
||||
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Close() error {
|
||||
it.sub.Unsubscribe()
|
||||
return nil
|
||||
}
|
||||
|
||||
// {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event raised by the {{$contract.Type}} contract.
|
||||
type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}}
|
||||
{{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type $structs}}{{else}}{{bindtype .Type $structs}}{{end}}; {{end}}
|
||||
Raw types.Log // Blockchain specific contextual infos
|
||||
}
|
||||
|
||||
// Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) {
|
||||
{{range .Normalized.Inputs}}
|
||||
{{if .Indexed}}var {{.Name}}Rule []interface{}
|
||||
for _, {{.Name}}Item := range {{.Name}} {
|
||||
{{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item)
|
||||
}{{end}}{{end}}
|
||||
|
||||
logs, sub, err := _{{$contract.Type}}.contract.FilterLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{$contract.Type}}{{.Normalized.Name}}Iterator{contract: _{{$contract.Type}}.contract, event: "{{.Original.Name}}", logs: logs, sub: sub}, nil
|
||||
}
|
||||
|
||||
// Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (event.Subscription, error) {
|
||||
{{range .Normalized.Inputs}}
|
||||
{{if .Indexed}}var {{.Name}}Rule []interface{}
|
||||
for _, {{.Name}}Item := range {{.Name}} {
|
||||
{{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item)
|
||||
}{{end}}{{end}}
|
||||
|
||||
logs, sub, err := _{{$contract.Type}}.contract.WatchLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return event.NewSubscription(func(quit <-chan struct{}) error {
|
||||
defer sub.Unsubscribe()
|
||||
for {
|
||||
select {
|
||||
case log := <-logs:
|
||||
// New log arrived, parse the event and forward to the user
|
||||
event := new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil {
|
||||
return err
|
||||
}
|
||||
event.Raw = log
|
||||
|
||||
select {
|
||||
case sink <- event:
|
||||
case err := <-sub.Err():
|
||||
return err
|
||||
case <-quit:
|
||||
return nil
|
||||
}
|
||||
case err := <-sub.Err():
|
||||
return err
|
||||
case <-quit:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}), nil
|
||||
}
|
||||
|
||||
// Parse{{.Normalized.Name}} is a log parse operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Parse{{.Normalized.Name}}(log types.Log) (*{{$contract.Type}}{{.Normalized.Name}}, error) {
|
||||
event := new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
event.Raw = log
|
||||
return event, nil
|
||||
}
|
||||
|
||||
{{end}}
|
||||
{{end}}
|
||||
`
|
||||
//
|
||||
//go:embed source.go.tpl
|
||||
var tmplSourceGo string
|
||||
|
|
|
|||
|
|
@ -64,6 +64,9 @@ type Type struct {
|
|||
var (
|
||||
// typeRegex parses the abi sub types
|
||||
typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
|
||||
|
||||
// sliceSizeRegex grab the slice size
|
||||
sliceSizeRegex = regexp.MustCompile("[0-9]+")
|
||||
)
|
||||
|
||||
// NewType creates a new reflection type of abi type given in t.
|
||||
|
|
@ -91,8 +94,7 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
|
|||
// grab the last cell and create a type from there
|
||||
sliced := t[i:]
|
||||
// grab the slice size with regexp
|
||||
re := regexp.MustCompile("[0-9]+")
|
||||
intz := re.FindAllString(sliced, -1)
|
||||
intz := sliceSizeRegex.FindAllString(sliced, -1)
|
||||
|
||||
if len(intz) == 0 {
|
||||
// is a slice
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ func TestWatchNewFile(t *testing.T) {
|
|||
func TestWatchNoDir(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Create ks but not the directory that it watches.
|
||||
dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watchnodir-test-%d-%d", os.Getpid(), rand.Int()))
|
||||
dir := filepath.Join(t.TempDir(), fmt.Sprintf("eth-keystore-watchnodir-test-%d-%d", os.Getpid(), rand.Int()))
|
||||
ks := NewKeyStore(dir, LightScryptN, LightScryptP)
|
||||
list := ks.Accounts()
|
||||
if len(list) > 0 {
|
||||
|
|
@ -126,7 +126,6 @@ func TestWatchNoDir(t *testing.T) {
|
|||
}
|
||||
// Create the directory and copy a key file into it.
|
||||
os.MkdirAll(dir, 0700)
|
||||
defer os.RemoveAll(dir)
|
||||
file := filepath.Join(dir, "aaa")
|
||||
if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -325,11 +324,7 @@ func TestUpdatedKeyfileContents(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
// Create a temporary keystore to test with
|
||||
dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-updatedkeyfilecontents-test-%d-%d", os.Getpid(), rand.Int()))
|
||||
|
||||
// Create the directory
|
||||
os.MkdirAll(dir, 0700)
|
||||
defer os.RemoveAll(dir)
|
||||
dir := t.TempDir()
|
||||
|
||||
ks := NewKeyStore(dir, LightScryptN, LightScryptP)
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,14 @@ var (
|
|||
DerivationSignatureHash = sha256.Sum256(common.Hash{}.Bytes())
|
||||
)
|
||||
|
||||
var (
|
||||
// PinRegexp is the regular expression used to validate PIN codes.
|
||||
pinRegexp = regexp.MustCompile(`^[0-9]{6,}$`)
|
||||
|
||||
// PukRegexp is the regular expression used to validate PUK codes.
|
||||
pukRegexp = regexp.MustCompile(`^[0-9]{12,}$`)
|
||||
)
|
||||
|
||||
// List of APDU command-related constants
|
||||
const (
|
||||
claISO7816 = 0
|
||||
|
|
@ -380,7 +388,7 @@ func (w *Wallet) Open(passphrase string) error {
|
|||
case passphrase == "":
|
||||
return ErrPINUnblockNeeded
|
||||
case status.PinRetryCount > 0:
|
||||
if !regexp.MustCompile(`^[0-9]{6,}$`).MatchString(passphrase) {
|
||||
if !pinRegexp.MatchString(passphrase) {
|
||||
w.log.Error("PIN needs to be at least 6 digits")
|
||||
return ErrPINNeeded
|
||||
}
|
||||
|
|
@ -388,7 +396,7 @@ func (w *Wallet) Open(passphrase string) error {
|
|||
return err
|
||||
}
|
||||
default:
|
||||
if !regexp.MustCompile(`^[0-9]{12,}$`).MatchString(passphrase) {
|
||||
if !pukRegexp.MatchString(passphrase) {
|
||||
w.log.Error("PUK needs to be at least 12 digits")
|
||||
return ErrPINUnblockNeeded
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -5,6 +5,8 @@
|
|||
syntax = "proto2";
|
||||
package hw.trezor.messages.common;
|
||||
|
||||
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||
|
||||
/**
|
||||
* Response: Success of the previous request
|
||||
* @end
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -5,6 +5,8 @@
|
|||
syntax = "proto2";
|
||||
package hw.trezor.messages.ethereum;
|
||||
|
||||
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||
|
||||
// Sugar for easier handling in Java
|
||||
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||
option java_outer_classname = "TrezorMessageEthereum";
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -5,6 +5,8 @@
|
|||
syntax = "proto2";
|
||||
package hw.trezor.messages.management;
|
||||
|
||||
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||
|
||||
// Sugar for easier handling in Java
|
||||
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||
option java_outer_classname = "TrezorMessageManagement";
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -9,10 +9,13 @@ package hw.trezor.messages;
|
|||
* Messages for TREZOR communication
|
||||
*/
|
||||
|
||||
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||
|
||||
// Sugar for easier handling in Java
|
||||
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||
option java_outer_classname = "TrezorMessage";
|
||||
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
// - Grab the latest Go plugin `go get -u github.com/golang/protobuf/protoc-gen-go`
|
||||
// - Vendor in the latest Go plugin `govendor fetch github.com/golang/protobuf/...`
|
||||
|
||||
//go:generate protoc -I/usr/local/include:. --go_out=import_path=trezor:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto
|
||||
//go:generate protoc -I/usr/local/include:. --go_out=paths=source_relative:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto
|
||||
|
||||
// Package trezor contains the wire protocol.
|
||||
package trezor
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ for:
|
|||
- image: Ubuntu
|
||||
build_script:
|
||||
- go run build/ci.go lint
|
||||
- go run build/ci.go generate -verify
|
||||
- go run build/ci.go install -dlgo
|
||||
test_script:
|
||||
- go run build/ci.go test -dlgo -short
|
||||
|
|
|
|||
|
|
@ -494,9 +494,6 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
|
|||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
stream.Close()
|
||||
|
||||
case event, ok := <-stream.Events:
|
||||
if !ok {
|
||||
log.Trace("Event stream closed")
|
||||
|
|
|
|||
|
|
@ -186,10 +186,14 @@ func (s *serverWithTimeout) eventCallback(event Event) {
|
|||
// call will just do nothing
|
||||
timer.Stop()
|
||||
delete(s.timeouts, id)
|
||||
s.childEventCb(event)
|
||||
if s.childEventCb != nil {
|
||||
s.childEventCb(event)
|
||||
}
|
||||
}
|
||||
default:
|
||||
s.childEventCb(event)
|
||||
if s.childEventCb != nil {
|
||||
s.childEventCb(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -211,25 +215,27 @@ func (s *serverWithTimeout) startTimeout(reqData RequestResponse) {
|
|||
delete(s.timeouts, id)
|
||||
childEventCb := s.childEventCb
|
||||
s.lock.Unlock()
|
||||
childEventCb(Event{Type: EvFail, Data: reqData})
|
||||
if childEventCb != nil {
|
||||
childEventCb(Event{Type: EvFail, Data: reqData})
|
||||
}
|
||||
})
|
||||
childEventCb := s.childEventCb
|
||||
s.lock.Unlock()
|
||||
childEventCb(Event{Type: EvTimeout, Data: reqData})
|
||||
if childEventCb != nil {
|
||||
childEventCb(Event{Type: EvTimeout, Data: reqData})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// unsubscribe stops all goroutines associated with the server.
|
||||
func (s *serverWithTimeout) unsubscribe() {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
for _, timer := range s.timeouts {
|
||||
if timer != nil {
|
||||
timer.Stop()
|
||||
}
|
||||
}
|
||||
s.childEventCb = nil
|
||||
s.lock.Unlock()
|
||||
s.parent.Unsubscribe()
|
||||
}
|
||||
|
||||
|
|
@ -328,10 +334,10 @@ func (s *serverWithLimits) eventCallback(event Event) {
|
|||
}
|
||||
childEventCb := s.childEventCb
|
||||
s.lock.Unlock()
|
||||
if passEvent {
|
||||
if passEvent && childEventCb != nil {
|
||||
childEventCb(event)
|
||||
}
|
||||
if sendCanRequestAgain {
|
||||
if sendCanRequestAgain && childEventCb != nil {
|
||||
childEventCb(Event{Type: EvCanRequestAgain})
|
||||
}
|
||||
}
|
||||
|
|
@ -347,13 +353,12 @@ func (s *serverWithLimits) sendRequest(request Request) (reqId ID) {
|
|||
// unsubscribe stops all goroutines associated with the server.
|
||||
func (s *serverWithLimits) unsubscribe() {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
if s.delayTimer != nil {
|
||||
s.delayTimer.Stop()
|
||||
s.delayTimer = nil
|
||||
}
|
||||
s.childEventCb = nil
|
||||
s.lock.Unlock()
|
||||
s.serverWithTimeout.unsubscribe()
|
||||
}
|
||||
|
||||
|
|
@ -383,7 +388,7 @@ func (s *serverWithLimits) canRequestNow() bool {
|
|||
}
|
||||
childEventCb := s.childEventCb
|
||||
s.lock.Unlock()
|
||||
if sendCanRequestAgain {
|
||||
if sendCanRequestAgain && childEventCb != nil {
|
||||
childEventCb(Event{Type: EvCanRequestAgain})
|
||||
}
|
||||
return canRequest
|
||||
|
|
@ -415,7 +420,7 @@ func (s *serverWithLimits) delay(delay time.Duration) {
|
|||
}
|
||||
childEventCb := s.childEventCb
|
||||
s.lock.Unlock()
|
||||
if sendCanRequestAgain {
|
||||
if sendCanRequestAgain && childEventCb != nil {
|
||||
childEventCb(Event{Type: EvCanRequestAgain})
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ func TestServerEvents(t *testing.T) {
|
|||
expEvent(EvFail)
|
||||
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}})
|
||||
expEvent(nil)
|
||||
srv.unsubscribe()
|
||||
}
|
||||
|
||||
func TestServerParallel(t *testing.T) {
|
||||
|
|
@ -129,9 +130,7 @@ func TestServerEventRateLimit(t *testing.T) {
|
|||
srv := NewServer(rs, clock)
|
||||
var eventCount int
|
||||
srv.subscribe(func(event Event) {
|
||||
if !event.IsRequestEvent() {
|
||||
eventCount++
|
||||
}
|
||||
eventCount++
|
||||
})
|
||||
expEvents := func(send, expAllowed int) {
|
||||
eventCount = 0
|
||||
|
|
@ -147,6 +146,30 @@ func TestServerEventRateLimit(t *testing.T) {
|
|||
expEvents(5, 1)
|
||||
clock.Run(maxServerEventRate * maxServerEventBuffer * 2)
|
||||
expEvents(maxServerEventBuffer+5, maxServerEventBuffer)
|
||||
srv.unsubscribe()
|
||||
}
|
||||
|
||||
func TestServerUnsubscribe(t *testing.T) {
|
||||
rs := &testRequestServer{}
|
||||
clock := &mclock.Simulated{}
|
||||
srv := NewServer(rs, clock)
|
||||
var eventCount int
|
||||
srv.subscribe(func(event Event) {
|
||||
eventCount++
|
||||
})
|
||||
eventCb := rs.eventCb
|
||||
eventCb(Event{Type: testEventType})
|
||||
if eventCount != 1 {
|
||||
t.Errorf("Server event callback not called before unsubscribe")
|
||||
}
|
||||
srv.unsubscribe()
|
||||
if rs.eventCb != nil {
|
||||
t.Errorf("Server event callback not removed after unsubscribe")
|
||||
}
|
||||
eventCb(Event{Type: testEventType})
|
||||
if eventCount != 1 {
|
||||
t.Errorf("Server event callback called after unsubscribe")
|
||||
}
|
||||
}
|
||||
|
||||
type testRequestServer struct {
|
||||
|
|
@ -156,4 +179,4 @@ type testRequestServer struct {
|
|||
func (rs *testRequestServer) Name() string { return "" }
|
||||
func (rs *testRequestServer) Subscribe(eventCb func(Event)) { rs.eventCb = eventCb }
|
||||
func (rs *testRequestServer) SendRequest(ID, Request) {}
|
||||
func (rs *testRequestServer) Unsubscribe() {}
|
||||
func (rs *testRequestServer) Unsubscribe() { rs.eventCb = nil }
|
||||
|
|
|
|||
|
|
@ -173,24 +173,24 @@ type TestCommitteeChain struct {
|
|||
init bool
|
||||
}
|
||||
|
||||
func (t *TestCommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error {
|
||||
t.fsp, t.nsp, t.init = bootstrap.Header.SyncPeriod(), bootstrap.Header.SyncPeriod()+2, true
|
||||
func (tc *TestCommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error {
|
||||
tc.fsp, tc.nsp, tc.init = bootstrap.Header.SyncPeriod(), bootstrap.Header.SyncPeriod()+2, true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestCommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error {
|
||||
func (tc *TestCommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error {
|
||||
period := update.AttestedHeader.Header.SyncPeriod()
|
||||
if period < t.fsp || period > t.nsp || !t.init {
|
||||
if period < tc.fsp || period > tc.nsp || !tc.init {
|
||||
return light.ErrInvalidPeriod
|
||||
}
|
||||
if period == t.nsp {
|
||||
t.nsp++
|
||||
if period == tc.nsp {
|
||||
tc.nsp++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestCommitteeChain) NextSyncPeriod() (uint64, bool) {
|
||||
return t.nsp, t.init
|
||||
func (tc *TestCommitteeChain) NextSyncPeriod() (uint64, bool) {
|
||||
return tc.nsp, tc.init
|
||||
}
|
||||
|
||||
func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) {
|
||||
|
|
@ -199,8 +199,8 @@ func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *TestCommitteeChain) SetNextSyncPeriod(nsp uint64) {
|
||||
t.init, t.nsp = true, nsp
|
||||
func (tc *TestCommitteeChain) SetNextSyncPeriod(nsp uint64) {
|
||||
tc.init, tc.nsp = true, nsp
|
||||
}
|
||||
|
||||
func (tc *TestCommitteeChain) ExpNextSyncPeriod(t *testing.T, expNsp uint64) {
|
||||
|
|
|
|||
|
|
@ -5,55 +5,55 @@
|
|||
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
|
||||
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
|
||||
|
||||
# version:golang 1.22.4
|
||||
# version:golang 1.22.5
|
||||
# https://go.dev/dl/
|
||||
fed720678e728a7ca30ba8d1ded1caafe27d16028fab0232b8ba8e22008fb784 go1.22.4.src.tar.gz
|
||||
b9647fa9fc83a0cc5d4f092a19eaeaecf45f063a5aa7d4962fde65aeb7ae6ce1 go1.22.4.aix-ppc64.tar.gz
|
||||
7788f40f3a46f201df1dc46ca640403eb535d5513fc33449164a90dbd229b761 go1.22.4.darwin-amd64.pkg
|
||||
c95967f50aa4ace34af0c236cbdb49a9a3e80ee2ad09d85775cb4462a5c19ed3 go1.22.4.darwin-amd64.tar.gz
|
||||
4036c88faf57a6b096916f1827edcdbf5290a47cc5f59956e88cdd9b1b71088c go1.22.4.darwin-arm64.pkg
|
||||
242b78dc4c8f3d5435d28a0d2cec9b4c1aa999b601fb8aa59fb4e5a1364bf827 go1.22.4.darwin-arm64.tar.gz
|
||||
f2fbb51af4719d3616efb482d6ed2b96579b474156f85a7ddc6f126764feec4b go1.22.4.dragonfly-amd64.tar.gz
|
||||
7c54884bb9f274884651d41e61d1bc12738863ad1497e97ea19ad0e9aa6bf7b5 go1.22.4.freebsd-386.tar.gz
|
||||
88d44500e1701dd35797619774d6dd51bf60f45a8338b0a82ddc018e4e63fb78 go1.22.4.freebsd-amd64.tar.gz
|
||||
3d9efe47db142a22679aba46b1772e3900b0d87ae13bd2b3bc80dbf2ac0b2cd6 go1.22.4.freebsd-arm.tar.gz
|
||||
726dc093cf020277be45debf03c3b02b43c2efb3e2a5d4fba8f52579d65327dc go1.22.4.freebsd-arm64.tar.gz
|
||||
5f6b67e5e32f1d6ccb2d4dcb44934a5e2e870a877ba7443d86ec43cfc28afa71 go1.22.4.freebsd-riscv64.tar.gz
|
||||
d56ecc2f85b6418a21ef83879594d0c42ab4f65391a676bb12254870e6690d63 go1.22.4.illumos-amd64.tar.gz
|
||||
47a2a8d249a91eb8605c33bceec63aedda0441a43eac47b4721e3975ff916cec go1.22.4.linux-386.tar.gz
|
||||
ba79d4526102575196273416239cca418a651e049c2b099f3159db85e7bade7d go1.22.4.linux-amd64.tar.gz
|
||||
a8e177c354d2e4a1b61020aca3562e27ea3e8f8247eca3170e3fa1e0c2f9e771 go1.22.4.linux-arm64.tar.gz
|
||||
e2b143fbacbc9cbd448e9ef41ac3981f0488ce849af1cf37e2341d09670661de go1.22.4.linux-armv6l.tar.gz
|
||||
e2ff9436e4b34bf6926b06d97916e26d67a909a2effec17967245900f0816f1d go1.22.4.linux-loong64.tar.gz
|
||||
73f0dcc60458c4770593b05a7bc01cc0d31fc98f948c0c2334812c7a1f2fc3f1 go1.22.4.linux-mips.tar.gz
|
||||
417af97fc2630a647052375768be4c38adcc5af946352ea5b28613ea81ca5d45 go1.22.4.linux-mips64.tar.gz
|
||||
7486e2d7dd8c98eb44df815ace35a7fe7f30b7c02326e3741bd934077508139b go1.22.4.linux-mips64le.tar.gz
|
||||
69479c8aad301e459a8365b40cad1074a0dbba5defb9291669f94809c4c4be6e go1.22.4.linux-mipsle.tar.gz
|
||||
dd238847e65bc3e2745caca475a5db6522a2fcf85cf6c38fc36a06642b19efd7 go1.22.4.linux-ppc64.tar.gz
|
||||
a3e5834657ef92523f570f798fed42f1f87bc18222a16815ec76b84169649ec4 go1.22.4.linux-ppc64le.tar.gz
|
||||
56a827ff7dc6245bcd7a1e9288dffaa1d8b0fd7468562264c1523daf3b4f1b4a go1.22.4.linux-riscv64.tar.gz
|
||||
7590c3e278e2dc6040aae0a39da3ca1eb2e3921673a7304cc34d588c45889eec go1.22.4.linux-s390x.tar.gz
|
||||
ddd2eebe34471a2502de6c5dad04ab27c9fc80cbde7a9ad5b3c66ecec4504e1d go1.22.4.netbsd-386.tar.gz
|
||||
33af79f6f935f6fbacc5d23876450b3567b79348fc065beef8e64081127dd234 go1.22.4.netbsd-amd64.tar.gz
|
||||
fa3550ebd5375a70b3bcd342b5a71f4bd271dcbbfaf4eabefa2144ab5d8924b6 go1.22.4.netbsd-arm.tar.gz
|
||||
c9a2971dec9f6d320c6f2b049b2353c6d0a2d35e87b8a4b2d78a2f0d62545f8e go1.22.4.netbsd-arm64.tar.gz
|
||||
d21af022331bfdc2b5b161d616c3a1a4573d33cf7a30416ee509a8f3641deb47 go1.22.4.openbsd-386.tar.gz
|
||||
72c0094c43f7e5722ec49c2a3e9dfa7a1123ac43a5f3a63eecf3e3795d3ff0ae go1.22.4.openbsd-amd64.tar.gz
|
||||
1096831ea3c5ea3ca57d14251d9eda3786889531eb40d7d6775dcaa324d4b065 go1.22.4.openbsd-arm.tar.gz
|
||||
a7ab8d4e0b02bf06ed144ba42c61c0e93ee00f2b433415dfd4ad4b6e79f31650 go1.22.4.openbsd-arm64.tar.gz
|
||||
9716327c8a628358798898dc5148c49dbbeb5196bf2cbf088e550721a6e4f60b go1.22.4.openbsd-ppc64.tar.gz
|
||||
a8dd4503c95c32a502a616ab78870a19889c9325fe9bd31eb16dd69346e4bfa8 go1.22.4.plan9-386.tar.gz
|
||||
5423a25808d76fe5aca8607a2e5ac5673abf45446b168cb5e9d8519ee9fe39a1 go1.22.4.plan9-amd64.tar.gz
|
||||
6af939ad583f5c85c09c53728ab7d38c3cc2b39167562d6c18a07c5c6608b370 go1.22.4.plan9-arm.tar.gz
|
||||
e8cabe69c03085725afdb32a6f9998191a3e55a747b270d835fd05000d56abba go1.22.4.solaris-amd64.tar.gz
|
||||
5c6446e2ea80bc6a971d2b34446f16e6517e638b0ff8d3ea229228d1931790b0 go1.22.4.windows-386.msi
|
||||
aca4e2c37278a10f1c70dd0df142f7d66b50334fcee48978d409202d308d6d25 go1.22.4.windows-386.zip
|
||||
3c21105d7b584759b6e266383b777caf6e87142d304a10b539dbc66ab482bb5f go1.22.4.windows-amd64.msi
|
||||
26321c4d945a0035d8a5bc4a1965b0df401ff8ceac66ce2daadabf9030419a98 go1.22.4.windows-amd64.zip
|
||||
c4303f02b864304eb83dd1db0b4ebf9d2ec9d216e7ef44a7657b166a52889c7f go1.22.4.windows-arm.msi
|
||||
5fcd0671a49cecf39b41021621ee1b6e7aa1370f37122b72e80d4fd4185833b6 go1.22.4.windows-arm.zip
|
||||
553cc6c460f4e3eb4fad5b897c0bb22cd8bbeb20929f0e3eeb939420320292ce go1.22.4.windows-arm64.msi
|
||||
8a2daa9ea28cbdafddc6171aefed384f4e5b6e714fb52116fe9ed25a132f37ed go1.22.4.windows-arm64.zip
|
||||
ac9c723f224969aee624bc34fd34c9e13f2a212d75c71c807de644bb46e112f6 go1.22.5.src.tar.gz
|
||||
c82ba3403c45a4aa4b84b08244656a51e55b86fb130dcc500f5291d0f3b12222 go1.22.5.aix-ppc64.tar.gz
|
||||
8a8872b1bac959b3b76f2e3978c46406d22a54a99c83ca55840ca08b4f2960bc go1.22.5.darwin-amd64.pkg
|
||||
95d9933cdcf45f211243c42c7705c37353cccd99f27eb4d8e2d1bf2f4165cb50 go1.22.5.darwin-amd64.tar.gz
|
||||
8c943512d1fa4e849f0078b03721df02aac19d8bb872dd17ab3ee7127ae6b732 go1.22.5.darwin-arm64.pkg
|
||||
4cd1bcb05be03cecb77bccd765785d5ff69d79adf4dd49790471d00c06b41133 go1.22.5.darwin-arm64.tar.gz
|
||||
1f1f035e968a877cd8ed62adae6edb2feeee62470660b7587ddcb904a3877a21 go1.22.5.dragonfly-amd64.tar.gz
|
||||
d660698411465531d475ec1c617fdb415df68740f3511138a8d15506665a06f9 go1.22.5.freebsd-386.tar.gz
|
||||
75f43ef46c2ad46c534ded25d26fba9bef036fc07074dfa45c0b3b90856a8151 go1.22.5.freebsd-amd64.tar.gz
|
||||
75614714e7e4a4dd721f0eddd6555b3f6afc4c07e59c1b9b769cf663996165f9 go1.22.5.freebsd-arm.tar.gz
|
||||
1377d0d7233f1b8f4cb8e3456f2e7ed44aca4a95daab79ae09605d34aa967c6b go1.22.5.freebsd-arm64.tar.gz
|
||||
07baf198587abc05ea789dbe5810a2d6612ad56a51718bbf74de2c93bdbe676a go1.22.5.freebsd-riscv64.tar.gz
|
||||
c0bd4f0d44252f3ec93ca850a41b167bb868179c7c283f8af9439e73b2654b17 go1.22.5.illumos-amd64.tar.gz
|
||||
3ea4c78e6fa52978ae1ed2e5927ad17495da440c9fae7787b1ebc1d0572f7f43 go1.22.5.linux-386.tar.gz
|
||||
904b924d435eaea086515bc63235b192ea441bd8c9b198c507e85009e6e4c7f0 go1.22.5.linux-amd64.tar.gz
|
||||
8d21325bfcf431be3660527c1a39d3d9ad71535fabdf5041c826e44e31642b5a go1.22.5.linux-arm64.tar.gz
|
||||
8c4587cf3e63c9aefbcafa92818c4d9d51683af93ea687bf6c7508d6fa36f85e go1.22.5.linux-armv6l.tar.gz
|
||||
780e2eeb6376a763c564f776eaac6700f33f95e29302faa54b040b19cb1f6fd2 go1.22.5.linux-loong64.tar.gz
|
||||
f784aa1adfb605da3bfe8cd534b545bddae3eb893e9302f7c2f5d44656b1cae2 go1.22.5.linux-mips.tar.gz
|
||||
aaa3756571467768388f2ab641a02ff54f98f1684808cda047a7be3026e4b438 go1.22.5.linux-mips64.tar.gz
|
||||
b7956d925c9ef5a4dc53017feaed2d78dba5d0a1036bad5ea513f1f15ba08fbc go1.22.5.linux-mips64le.tar.gz
|
||||
7baf605be9b787acd750b6b48a91818a5590ec9289b14aea5696a46b41853888 go1.22.5.linux-mipsle.tar.gz
|
||||
f09b2a6c1a409662e8e8fe267e1eabeba0a1fd00eb1422fd88297b013803952e go1.22.5.linux-ppc64.tar.gz
|
||||
5312bb420ac0b59175a58927e70b4660b14ab7319aab54398b6071fabcbfbb09 go1.22.5.linux-ppc64le.tar.gz
|
||||
f8d0c7d96b336f4133409ff9da7241cfe91e65723c2e8e7c7f9b58a9f9603476 go1.22.5.linux-riscv64.tar.gz
|
||||
24c6c5c9d515adea5d58ae78388348c97614a0c21ac4d4f4c0dab75e893b0b5d go1.22.5.linux-s390x.tar.gz
|
||||
39144c62acbaa85e4f1ab57bad8f5b3dc67d6fa24b711ec1fa593f4a0ea1fe91 go1.22.5.netbsd-386.tar.gz
|
||||
118f79640588eb878529b46cdf56599012da6575f0ac07069ec1e9a8e78ddd0b go1.22.5.netbsd-amd64.tar.gz
|
||||
d39c2b94ae3fd0a6399e545cbecb673496293075291bd98ef15f24d21625a490 go1.22.5.netbsd-arm.tar.gz
|
||||
f7fb617d10c39248996521d72370db82d50724fa894089c76ae4298fbbe1fb0b go1.22.5.netbsd-arm64.tar.gz
|
||||
e0f778a34746587ae7c18e8a24cfaba1b2eaabce75d0ceb470adf576ad1cd90f go1.22.5.openbsd-386.tar.gz
|
||||
b417311df26ef7ae8b34fcb991519a5c496010561c12386d9469aea03c1bdf0b go1.22.5.openbsd-amd64.tar.gz
|
||||
e78e8ad05605d530a4f79e55031c7c65f2020a9d442e05d490bd08f0d947a34f go1.22.5.openbsd-arm.tar.gz
|
||||
8027898948f17742717786ead2ff2e960ee1fc82995d6edbad0050d551710f59 go1.22.5.openbsd-arm64.tar.gz
|
||||
99c5b81d75bcc0d83d25dedc9535682c42c0e761276c88bcc4db6340344644fd go1.22.5.openbsd-ppc64.tar.gz
|
||||
30d5dacdee0481f0b8cabb75b706465e2177c3a4a1d1c46293332f4b90a3d199 go1.22.5.plan9-386.tar.gz
|
||||
65628650cd7665387cfe6fa386c381f4de1ef7b03a12067ae9ccf06d2feaea2c go1.22.5.plan9-amd64.tar.gz
|
||||
322541cbfc9ae95b48b9eec4eb45df48299784592e23121084f790cf1082787e go1.22.5.plan9-arm.tar.gz
|
||||
87c590e3eb81fcffa3dc1524c03c2847f0890e95c2a43586e82b56c262eb03d8 go1.22.5.solaris-amd64.tar.gz
|
||||
3ec89ed822b38f4483977a90913fbe39d0857f0ed16c4642dec1950ddbe8c943 go1.22.5.windows-386.msi
|
||||
c44fc421075022add78fbf8db38519dd5520a11832749be2189e64b3cf4f02f9 go1.22.5.windows-386.zip
|
||||
86b0299ab8cb9c44882a9080dac03f7f4d9546f51ed1ba1015599114bcbc66d0 go1.22.5.windows-amd64.msi
|
||||
59968438b8d90f108fd240d4d2f95b037e59716995f7409e0a322dcb996e9f42 go1.22.5.windows-amd64.zip
|
||||
013d3b300e6b8f26482d6dd17b02830b83ee63795498bd8c0c9d80bb2c4d6cf7 go1.22.5.windows-arm.msi
|
||||
8cc860630a84e2dbff3e84280f46a571741f26f8a1819aa4fbcb3164fdd51312 go1.22.5.windows-arm.zip
|
||||
8f90519d9f305f2caa05d1d4fb0656b50f1bf89d76e194279f480e5a484c891f go1.22.5.windows-arm64.msi
|
||||
6717d5841162aa8c05f932eb74a643f1310b8a88f80f0830e86d194289734bbf go1.22.5.windows-arm64.zip
|
||||
|
||||
# version:golangci 1.59.0
|
||||
# https://github.com/golangci/golangci-lint/releases/
|
||||
|
|
@ -99,3 +99,28 @@ d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.t
|
|||
# version:ppa-builder-2 1.21.9
|
||||
# https://go.dev/dl/
|
||||
58f0c5ced45a0012bce2ff7a9df03e128abcc8818ebabe5027bb92bafe20e421 go1.21.9.src.tar.gz
|
||||
|
||||
# version:protoc 27.1
|
||||
# https://github.com/protocolbuffers/protobuf/releases/
|
||||
# https://github.com/protocolbuffers/protobuf/releases/download/v27.1/
|
||||
8809c2ec85368c6b6e9af161b6771a153aa92670a24adbe46dd34fa02a04df2f protoc-27.1-linux-aarch_64.zip
|
||||
5d21979a6d27475e810b76b88863d1e784fa01ffb15e511a3ec5bd1924d89426 protoc-27.1-linux-ppcle_64.zip
|
||||
84d8852750ed186dc4a057a1a86bcac409be5362d6af04770f42367fee6b7bc1 protoc-27.1-linux-s390_64.zip
|
||||
2f028796ff5741691650e0eea290e61ff2f1c0d87f8d31fe45ef47fd967cef0c protoc-27.1-linux-x86_32.zip
|
||||
8970e3d8bbd67d53768fe8c2e3971bdd71e51cfe2001ca06dacad17258a7dae3 protoc-27.1-linux-x86_64.zip
|
||||
03b7af1bf469e7285dc51976ee5fa99412704dbd1c017105114852a37b165c12 protoc-27.1-osx-aarch_64.zip
|
||||
f14d3973cf13283d07c520ed6f4c12405ad41b9efd18089a1c74897037d742b5 protoc-27.1-osx-universal_binary.zip
|
||||
8520d944f3a3890fa296a3b3b0d4bb18337337e2526bbbf1b507eeea3c2a1ec4 protoc-27.1-osx-x86_64.zip
|
||||
6263718ff96547b8392a079f6fdf02a4156f2e8d13cd51649a0d03fb7afa2de8 protoc-27.1-win32.zip
|
||||
da531c51ccd1290d8d34821f0ce4e219c7fbaa6f9825f5a3fb092a9d03fe6206 protoc-27.1-win64.zip
|
||||
|
||||
# version:protoc-gen-go 1.34.2
|
||||
# https://github.com/protocolbuffers/protobuf-go/releases/
|
||||
# https://github.com/protocolbuffers/protobuf-go/releases/download/v1.34.2/
|
||||
9b48d8f90add02e8e94e14962fed74e7ce2b2d6bda4dd42f1f4fbccf0f766f1a protoc-gen-go.v1.34.2.darwin.amd64.tar.gz
|
||||
17aca7f948dbb624049030cf841e35895cf34183ba006e721247fdeb95ff2780 protoc-gen-go.v1.34.2.darwin.arm64.tar.gz
|
||||
a191849433fd489f1d44f37788d762658f3f5fb225f3a85d4ce6ba32666703ed protoc-gen-go.v1.34.2.linux.386.tar.gz
|
||||
b87bc134dee55576a842141bf0ed27761c635d746780fce5dee038c6dd16554f protoc-gen-go.v1.34.2.linux.amd64.tar.gz
|
||||
63d400167e75ab9f6690688f6fdc6a9455aa20bc1faa71e32149dbd322f7f198 protoc-gen-go.v1.34.2.linux.arm64.tar.gz
|
||||
56e7675816db6e62be4f833a51544d5716b8420c462515579e05ca8444ab06ed protoc-gen-go.v1.34.2.windows.386.zip
|
||||
abafd39612177dd4e9a65207cadd5374a9352d8611e8e040f8462fcfa3010daf protoc-gen-go.v1.34.2.windows.amd64.zip
|
||||
|
|
|
|||
174
build/ci.go
174
build/ci.go
|
|
@ -39,9 +39,11 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -169,6 +171,8 @@ func main() {
|
|||
doPurge(os.Args[2:])
|
||||
case "sanitycheck":
|
||||
doSanityCheck()
|
||||
case "generate":
|
||||
doGenerate()
|
||||
default:
|
||||
log.Fatal("unknown command ", os.Args[1])
|
||||
}
|
||||
|
|
@ -345,6 +349,86 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string {
|
|||
return filepath.Join(cachedir, base)
|
||||
}
|
||||
|
||||
// hashSourceFiles iterates all files under the top-level project directory
|
||||
// computing the hash of each file (excluding files within the tests
|
||||
// subrepo)
|
||||
func hashSourceFiles() (map[string]common.Hash, error) {
|
||||
res := make(map[string]common.Hash)
|
||||
err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
|
||||
if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if !d.Type().IsRegular() {
|
||||
return nil
|
||||
}
|
||||
// open the file and hash it
|
||||
f, err := os.OpenFile(path, os.O_RDONLY, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hasher := sha256.New()
|
||||
if _, err := io.Copy(hasher, f); err != nil {
|
||||
return err
|
||||
}
|
||||
res[path] = common.Hash(hasher.Sum(nil))
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// doGenerate ensures that re-generating generated files does not cause
|
||||
// any mutations in the source file tree: i.e. all generated files were
|
||||
// updated and committed. Any stale generated files are updated.
|
||||
func doGenerate() {
|
||||
var (
|
||||
tc = new(build.GoToolchain)
|
||||
cachedir = flag.String("cachedir", "./build/cache", "directory for caching binaries.")
|
||||
verify = flag.Bool("verify", false, "check whether any files are changed by go generate")
|
||||
)
|
||||
|
||||
protocPath := downloadProtoc(*cachedir)
|
||||
protocGenGoPath := downloadProtocGenGo(*cachedir)
|
||||
|
||||
var preHashes map[string]common.Hash
|
||||
if *verify {
|
||||
var err error
|
||||
preHashes, err = hashSourceFiles()
|
||||
if err != nil {
|
||||
log.Fatal("failed to compute map of source hashes", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
c := tc.Go("generate", "./...")
|
||||
pathList := []string{filepath.Join(protocPath, "bin"), protocGenGoPath, os.Getenv("PATH")}
|
||||
c.Env = append(c.Env, "PATH="+strings.Join(pathList, string(os.PathListSeparator)))
|
||||
build.MustRun(c)
|
||||
|
||||
if !*verify {
|
||||
return
|
||||
}
|
||||
// Check if files were changed.
|
||||
postHashes, err := hashSourceFiles()
|
||||
if err != nil {
|
||||
log.Fatal("error computing source tree file hashes", "err", err)
|
||||
}
|
||||
updates := []string{}
|
||||
for path, postHash := range postHashes {
|
||||
preHash, ok := preHashes[path]
|
||||
if !ok || preHash != postHash {
|
||||
updates = append(updates, path)
|
||||
}
|
||||
}
|
||||
for _, updatedFile := range updates {
|
||||
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile)
|
||||
}
|
||||
if len(updates) != 0 {
|
||||
log.Fatal("One or more generated files were updated by running 'go generate ./...'")
|
||||
}
|
||||
}
|
||||
|
||||
// doLint runs golangci-lint on requested packages.
|
||||
func doLint(cmdline []string) {
|
||||
var (
|
||||
|
|
@ -390,6 +474,96 @@ func downloadLinter(cachedir string) string {
|
|||
return filepath.Join(cachedir, base, "golangci-lint")
|
||||
}
|
||||
|
||||
// protocArchiveBaseName returns the name of the protoc archive file for
|
||||
// the current system, stripped of version and file suffix.
|
||||
func protocArchiveBaseName() (string, error) {
|
||||
switch runtime.GOOS + "-" + runtime.GOARCH {
|
||||
case "windows-amd64":
|
||||
return "win64", nil
|
||||
case "windows-386":
|
||||
return "win32", nil
|
||||
case "linux-arm64":
|
||||
return "linux-aarch_64", nil
|
||||
case "linux-386":
|
||||
return "linux-x86_32", nil
|
||||
case "linux-amd64":
|
||||
return "linux-x86_64", nil
|
||||
case "darwin-arm64":
|
||||
return "osx-aarch_64", nil
|
||||
case "darwin-amd64":
|
||||
return "osx-x86_64", nil
|
||||
default:
|
||||
return "", fmt.Errorf("no prebuilt release of protoc available for this system (os: %s, arch: %s)", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
}
|
||||
|
||||
// downloadProtocGenGo downloads protoc-gen-go, which is used by protoc
|
||||
// in the generate command. It returns the full path of the directory
|
||||
// containing the 'protoc-gen-go' executable.
|
||||
func downloadProtocGenGo(cachedir string) string {
|
||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||
version, err := build.Version(csdb, "protoc-gen-go")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
baseName := fmt.Sprintf("protoc-gen-go.v%s.%s.%s", version, runtime.GOOS, runtime.GOARCH)
|
||||
archiveName := baseName
|
||||
if runtime.GOOS == "windows" {
|
||||
archiveName += ".zip"
|
||||
} else {
|
||||
archiveName += ".tar.gz"
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://github.com/protocolbuffers/protobuf-go/releases/download/v%s/%s", version, archiveName)
|
||||
|
||||
archivePath := path.Join(cachedir, archiveName)
|
||||
if err := csdb.DownloadFile(url, archivePath); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
extractDest := filepath.Join(cachedir, baseName)
|
||||
if err := build.ExtractArchive(archivePath, extractDest); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
extractDest, err = filepath.Abs(extractDest)
|
||||
if err != nil {
|
||||
log.Fatal("error resolving absolute path for protoc", "err", err)
|
||||
}
|
||||
return extractDest
|
||||
}
|
||||
|
||||
// downloadProtoc downloads the prebuilt protoc binary used to lint generated
|
||||
// files as a CI step. It returns the full path to the directory containing
|
||||
// the protoc executable.
|
||||
func downloadProtoc(cachedir string) string {
|
||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||
version, err := build.Version(csdb, "protoc")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
baseName, err := protocArchiveBaseName()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fileName := fmt.Sprintf("protoc-%s-%s", version, baseName)
|
||||
archiveFileName := fileName + ".zip"
|
||||
url := fmt.Sprintf("https://github.com/protocolbuffers/protobuf/releases/download/v%s/%s", version, archiveFileName)
|
||||
archivePath := filepath.Join(cachedir, archiveFileName)
|
||||
|
||||
if err := csdb.DownloadFile(url, archivePath); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
extractDest := filepath.Join(cachedir, fileName)
|
||||
if err := build.ExtractArchive(archivePath, extractDest); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
extractDest, err = filepath.Abs(extractDest)
|
||||
if err != nil {
|
||||
log.Fatal("error resolving absolute path for protoc", "err", err)
|
||||
}
|
||||
return extractDest
|
||||
}
|
||||
|
||||
// Release Packaging
|
||||
func doArchive(cmdline []string) {
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -19,39 +19,21 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/beacon/blsync"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/internal/debug"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
verbosityFlag = &cli.IntFlag{
|
||||
Name: "verbosity",
|
||||
Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail",
|
||||
Value: 3,
|
||||
Category: flags.LoggingCategory,
|
||||
}
|
||||
vmoduleFlag = &cli.StringFlag{
|
||||
Name: "vmodule",
|
||||
Usage: "Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. eth/*=5,p2p=4)",
|
||||
Value: "",
|
||||
Hidden: true,
|
||||
Category: flags.LoggingCategory,
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := flags.NewApp("beacon light syncer tool")
|
||||
app.Flags = []cli.Flag{
|
||||
app.Flags = flags.Merge([]cli.Flag{
|
||||
utils.BeaconApiFlag,
|
||||
utils.BeaconApiHeaderFlag,
|
||||
utils.BeaconThresholdFlag,
|
||||
|
|
@ -66,8 +48,16 @@ func main() {
|
|||
utils.GoerliFlag,
|
||||
utils.BlsyncApiFlag,
|
||||
utils.BlsyncJWTSecretFlag,
|
||||
verbosityFlag,
|
||||
vmoduleFlag,
|
||||
},
|
||||
debug.Flags,
|
||||
)
|
||||
app.Before = func(ctx *cli.Context) error {
|
||||
flags.MigrateGlobalFlags(ctx)
|
||||
return debug.Setup(ctx)
|
||||
}
|
||||
app.After = func(ctx *cli.Context) error {
|
||||
debug.Exit()
|
||||
return nil
|
||||
}
|
||||
app.Action = sync
|
||||
|
||||
|
|
@ -78,14 +68,6 @@ func main() {
|
|||
}
|
||||
|
||||
func sync(ctx *cli.Context) error {
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
output := io.Writer(os.Stderr)
|
||||
if usecolor {
|
||||
output = colorable.NewColorable(os.Stderr)
|
||||
}
|
||||
verbosity := log.FromLegacyLevel(ctx.Int(verbosityFlag.Name))
|
||||
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(output, verbosity, usecolor)))
|
||||
|
||||
// set up blsync
|
||||
client := blsync.NewClient(ctx)
|
||||
client.SetEngineRPC(makeRPCClient(ctx))
|
||||
|
|
|
|||
|
|
@ -225,8 +225,8 @@ Response
|
|||
- `value` [number:optional]: amount of Wei to send with the transaction
|
||||
- `data` [data:optional]: input data
|
||||
- `nonce` [number]: account nonce
|
||||
1. method signature [string:optional]
|
||||
- The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected.
|
||||
2. method signature [string:optional]
|
||||
- The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected.
|
||||
|
||||
|
||||
#### Result
|
||||
|
|
|
|||
|
|
@ -27,9 +27,8 @@ import (
|
|||
// TestImportRaw tests clef --importraw
|
||||
func TestImportRaw(t *testing.T) {
|
||||
t.Parallel()
|
||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||
keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
||||
t.Cleanup(func() { os.Remove(keyPath) })
|
||||
|
||||
t.Run("happy-path", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
@ -68,9 +67,8 @@ func TestImportRaw(t *testing.T) {
|
|||
// TestListAccounts tests clef --list-accounts
|
||||
func TestListAccounts(t *testing.T) {
|
||||
t.Parallel()
|
||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||
keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
||||
t.Cleanup(func() { os.Remove(keyPath) })
|
||||
|
||||
t.Run("no-accounts", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
@ -97,9 +95,8 @@ func TestListAccounts(t *testing.T) {
|
|||
// TestListWallets tests clef --list-wallets
|
||||
func TestListWallets(t *testing.T) {
|
||||
t.Parallel()
|
||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||
keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
||||
t.Cleanup(func() { os.Remove(keyPath) })
|
||||
|
||||
t.Run("no-accounts", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
|
|||
|
|
@ -34,12 +34,12 @@ import (
|
|||
"github.com/ethereum/go-ethereum/p2p"
|
||||
)
|
||||
|
||||
func makeJWTSecret() (string, [32]byte, error) {
|
||||
func makeJWTSecret(t *testing.T) (string, [32]byte, error) {
|
||||
var secret [32]byte
|
||||
if _, err := crand.Read(secret[:]); err != nil {
|
||||
return "", secret, fmt.Errorf("failed to create jwt secret: %v", err)
|
||||
}
|
||||
jwtPath := filepath.Join(os.TempDir(), "jwt_secret")
|
||||
jwtPath := filepath.Join(t.TempDir(), "jwt_secret")
|
||||
if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(secret[:])), 0600); err != nil {
|
||||
return "", secret, fmt.Errorf("failed to prepare jwt secret file: %v", err)
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@ func makeJWTSecret() (string, [32]byte, error) {
|
|||
}
|
||||
|
||||
func TestEthSuite(t *testing.T) {
|
||||
jwtPath, secret, err := makeJWTSecret()
|
||||
jwtPath, secret, err := makeJWTSecret(t)
|
||||
if err != nil {
|
||||
t.Fatalf("could not make jwt secret: %v", err)
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ func TestEthSuite(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSnapSuite(t *testing.T) {
|
||||
jwtPath, secret, err := makeJWTSecret()
|
||||
jwtPath, secret, err := makeJWTSecret(t)
|
||||
if err != nil {
|
||||
t.Fatalf("could not make jwt secret: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ func rlpxPing(ctx *cli.Context) error {
|
|||
}
|
||||
return fmt.Errorf("received disconnect message: %v", msg[0])
|
||||
default:
|
||||
return fmt.Errorf("invalid message code %d, expected handshake (code zero)", code)
|
||||
return fmt.Errorf("invalid message code %d, expected handshake (code zero) or disconnect (code one)", code)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,15 +14,15 @@ The `evm t8n` tool is a stateless state transition utility. It is a utility
|
|||
which can
|
||||
|
||||
1. Take a prestate, including
|
||||
- Accounts,
|
||||
- Block context information,
|
||||
- Previous blockshashes (*optional)
|
||||
- Accounts,
|
||||
- Block context information,
|
||||
- Previous blockshashes (*optional)
|
||||
2. Apply a set of transactions,
|
||||
3. Apply a mining-reward (*optional),
|
||||
4. And generate a post-state, including
|
||||
- State root, transaction root, receipt root,
|
||||
- Information about rejected transactions,
|
||||
- Optionally: a full or partial post-state dump
|
||||
- State root, transaction root, receipt root,
|
||||
- Information about rejected transactions,
|
||||
- Optionally: a full or partial post-state dump
|
||||
|
||||
### Specification
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ func blockTestCmd(ctx *cli.Context) error {
|
|||
continue
|
||||
}
|
||||
test := tests[name]
|
||||
if err := test.Run(false, rawdb.HashScheme, tracer, func(res error, chain *core.BlockChain) {
|
||||
if err := test.Run(false, rawdb.HashScheme, false, tracer, func(res error, chain *core.BlockChain) {
|
||||
if ctx.Bool(DumpFlag.Name) {
|
||||
if state, _ := chain.State(); state != nil {
|
||||
fmt.Println(string(state.Dump(nil)))
|
||||
|
|
|
|||
|
|
@ -306,7 +306,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
if tracer.Hooks.OnTxEnd != nil {
|
||||
tracer.Hooks.OnTxEnd(receipt, nil)
|
||||
}
|
||||
writeTraceResult(tracer, traceOutput)
|
||||
if err = writeTraceResult(tracer, traceOutput); err != nil {
|
||||
log.Warn("Error writing tracer output", "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -323,7 +325,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
var (
|
||||
blockReward = big.NewInt(miningReward)
|
||||
minerReward = new(big.Int).Set(blockReward)
|
||||
perOmmer = new(big.Int).Div(blockReward, big.NewInt(32))
|
||||
perOmmer = new(big.Int).Rsh(blockReward, 5)
|
||||
)
|
||||
for _, ommer := range pre.Env.Ommers {
|
||||
// Add 1/32th for each ommer included
|
||||
|
|
@ -332,7 +334,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
reward := big.NewInt(8)
|
||||
reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta))
|
||||
reward.Mul(reward, blockReward)
|
||||
reward.Div(reward, big.NewInt(8))
|
||||
reward.Rsh(reward, 3)
|
||||
statedb.AddBalance(ommer.Address, uint256.MustFromBig(reward), tracing.BalanceIncreaseRewardMineUncle)
|
||||
}
|
||||
statedb.AddBalance(pre.Env.Coinbase, uint256.MustFromBig(minerReward), tracing.BalanceIncreaseRewardMineBlock)
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ func Transition(ctx *cli.Context) error {
|
|||
// Set the chain id
|
||||
chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name))
|
||||
|
||||
if txIt, err = loadTransactions(txStr, inputData, prestate.Env, chainConfig); err != nil {
|
||||
if txIt, err = loadTransactions(txStr, inputData, chainConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := applyLondonChecks(&prestate.Env, chainConfig); err != nil {
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Tran
|
|||
return signedTxs, nil
|
||||
}
|
||||
|
||||
func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *params.ChainConfig) (txIterator, error) {
|
||||
func loadTransactions(txStr string, inputData *input, chainConfig *params.ChainConfig) (txIterator, error) {
|
||||
var txsWithKeys []*txWithKey
|
||||
if txStr != stdinSelector {
|
||||
data, err := os.ReadFile(txStr)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
|
@ -337,7 +336,7 @@ func importChain(ctx *cli.Context) error {
|
|||
fmt.Printf("Import done in %v.\n\n", time.Since(start))
|
||||
|
||||
// Output pre-compaction stats mostly to see the import trashing
|
||||
showLeveldbStats(db)
|
||||
showDBStats(db)
|
||||
|
||||
// Print the memory statistics used by the importing
|
||||
mem := new(runtime.MemStats)
|
||||
|
|
@ -360,7 +359,7 @@ func importChain(ctx *cli.Context) error {
|
|||
}
|
||||
fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
|
||||
|
||||
showLeveldbStats(db)
|
||||
showDBStats(db)
|
||||
return importErr
|
||||
}
|
||||
|
||||
|
|
@ -516,7 +515,7 @@ func importPreimages(ctx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func parseDumpConfig(ctx *cli.Context, stack *node.Node, db ethdb.Database) (*state.DumpConfig, common.Hash, error) {
|
||||
func parseDumpConfig(ctx *cli.Context, db ethdb.Database) (*state.DumpConfig, common.Hash, error) {
|
||||
var header *types.Header
|
||||
if ctx.NArg() > 1 {
|
||||
return nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg())
|
||||
|
|
@ -580,7 +579,7 @@ func dump(ctx *cli.Context) error {
|
|||
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||
defer db.Close()
|
||||
|
||||
conf, root, err := parseDumpConfig(ctx, stack, db)
|
||||
conf, root, err := parseDumpConfig(ctx, db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -407,17 +407,13 @@ func checkStateContent(ctx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func showLeveldbStats(db ethdb.KeyValueStater) {
|
||||
if stats, err := db.Stat("leveldb.stats"); err != nil {
|
||||
func showDBStats(db ethdb.KeyValueStater) {
|
||||
stats, err := db.Stat()
|
||||
if err != nil {
|
||||
log.Warn("Failed to read database stats", "error", err)
|
||||
} else {
|
||||
fmt.Println(stats)
|
||||
}
|
||||
if ioStats, err := db.Stat("leveldb.iostats"); err != nil {
|
||||
log.Warn("Failed to read database iostats", "error", err)
|
||||
} else {
|
||||
fmt.Println(ioStats)
|
||||
return
|
||||
}
|
||||
fmt.Println(stats)
|
||||
}
|
||||
|
||||
func dbStats(ctx *cli.Context) error {
|
||||
|
|
@ -427,7 +423,7 @@ func dbStats(ctx *cli.Context) error {
|
|||
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||
defer db.Close()
|
||||
|
||||
showLeveldbStats(db)
|
||||
showDBStats(db)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -439,7 +435,7 @@ func dbCompact(ctx *cli.Context) error {
|
|||
defer db.Close()
|
||||
|
||||
log.Info("Stats before compaction")
|
||||
showLeveldbStats(db)
|
||||
showDBStats(db)
|
||||
|
||||
log.Info("Triggering compaction")
|
||||
if err := db.Compact(nil, nil); err != nil {
|
||||
|
|
@ -447,7 +443,7 @@ func dbCompact(ctx *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
log.Info("Stats after compaction")
|
||||
showLeveldbStats(db)
|
||||
showDBStats(db)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ import (
|
|||
// TestExport does a basic test of "geth export", exporting the test-genesis.
|
||||
func TestExport(t *testing.T) {
|
||||
t.Parallel()
|
||||
outfile := fmt.Sprintf("%v/testExport.out", os.TempDir())
|
||||
defer os.Remove(outfile)
|
||||
outfile := fmt.Sprintf("%v/testExport.out", t.TempDir())
|
||||
geth := runGeth(t, "--datadir", initGeth(t), "export", outfile)
|
||||
geth.WaitExit()
|
||||
if have, want := geth.ExitStatus(), 0; have != want {
|
||||
|
|
|
|||
|
|
@ -201,9 +201,8 @@ func TestFileOut(t *testing.T) {
|
|||
var (
|
||||
have, want []byte
|
||||
err error
|
||||
path = fmt.Sprintf("%s/test_file_out-%d", os.TempDir(), rand.Int63())
|
||||
path = fmt.Sprintf("%s/test_file_out-%d", t.TempDir(), rand.Int63())
|
||||
)
|
||||
t.Cleanup(func() { os.Remove(path) })
|
||||
if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "logtest"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -222,9 +221,8 @@ func TestRotatingFileOut(t *testing.T) {
|
|||
var (
|
||||
have, want []byte
|
||||
err error
|
||||
path = fmt.Sprintf("%s/test_file_out-%d", os.TempDir(), rand.Int63())
|
||||
path = fmt.Sprintf("%s/test_file_out-%d", t.TempDir(), rand.Int63())
|
||||
)
|
||||
t.Cleanup(func() { os.Remove(path) })
|
||||
if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "--log.rotate", "logtest"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ var (
|
|||
utils.BeaconGenesisRootFlag,
|
||||
utils.BeaconGenesisTimeFlag,
|
||||
utils.BeaconCheckpointFlag,
|
||||
utils.CollectWitnessFlag,
|
||||
}, utils.NetworkFlags, utils.DatabaseFlags)
|
||||
|
||||
rpcFlags = []cli.Flag{
|
||||
|
|
|
|||
|
|
@ -544,7 +544,7 @@ func dumpState(ctx *cli.Context) error {
|
|||
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||
defer db.Close()
|
||||
|
||||
conf, root, err := parseDumpConfig(ctx, stack, db)
|
||||
conf, root, err := parseDumpConfig(ctx, db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,18 +29,12 @@ import (
|
|||
|
||||
// TestExport does basic sanity checks on the export/import functionality
|
||||
func TestExport(t *testing.T) {
|
||||
f := fmt.Sprintf("%v/tempdump", os.TempDir())
|
||||
defer func() {
|
||||
os.Remove(f)
|
||||
}()
|
||||
f := fmt.Sprintf("%v/tempdump", t.TempDir())
|
||||
testExport(t, f)
|
||||
}
|
||||
|
||||
func TestExportGzip(t *testing.T) {
|
||||
f := fmt.Sprintf("%v/tempdump.gz", os.TempDir())
|
||||
defer func() {
|
||||
os.Remove(f)
|
||||
}()
|
||||
f := fmt.Sprintf("%v/tempdump.gz", t.TempDir())
|
||||
testExport(t, f)
|
||||
}
|
||||
|
||||
|
|
@ -99,20 +93,14 @@ func testExport(t *testing.T, f string) {
|
|||
|
||||
// TestDeletionExport tests if the deletion markers can be exported/imported correctly
|
||||
func TestDeletionExport(t *testing.T) {
|
||||
f := fmt.Sprintf("%v/tempdump", os.TempDir())
|
||||
defer func() {
|
||||
os.Remove(f)
|
||||
}()
|
||||
f := fmt.Sprintf("%v/tempdump", t.TempDir())
|
||||
testDeletion(t, f)
|
||||
}
|
||||
|
||||
// TestDeletionExportGzip tests if the deletion markers can be exported/imported
|
||||
// correctly with gz compression.
|
||||
func TestDeletionExportGzip(t *testing.T) {
|
||||
f := fmt.Sprintf("%v/tempdump.gz", os.TempDir())
|
||||
defer func() {
|
||||
os.Remove(f)
|
||||
}()
|
||||
f := fmt.Sprintf("%v/tempdump.gz", t.TempDir())
|
||||
testDeletion(t, f)
|
||||
}
|
||||
|
||||
|
|
@ -171,10 +159,7 @@ func testDeletion(t *testing.T, f string) {
|
|||
// TestImportFutureFormat tests that we reject unsupported future versions.
|
||||
func TestImportFutureFormat(t *testing.T) {
|
||||
t.Parallel()
|
||||
f := fmt.Sprintf("%v/tempdump-future", os.TempDir())
|
||||
defer func() {
|
||||
os.Remove(f)
|
||||
}()
|
||||
f := fmt.Sprintf("%v/tempdump-future", t.TempDir())
|
||||
fh, err := os.OpenFile(f, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ var (
|
|||
}
|
||||
BeaconApiHeaderFlag = &cli.StringSliceFlag{
|
||||
Name: "beacon.api.header",
|
||||
Usage: "Pass custom HTTP header fields to the emote beacon node API in \"key:value\" format. This flag can be given multiple times.",
|
||||
Usage: "Pass custom HTTP header fields to the remote beacon node API in \"key:value\" format. This flag can be given multiple times.",
|
||||
Category: flags.BeaconCategory,
|
||||
}
|
||||
BeaconThresholdFlag = &cli.IntFlag{
|
||||
|
|
@ -604,6 +604,11 @@ var (
|
|||
Usage: "Disables db compaction after import",
|
||||
Category: flags.LoggingCategory,
|
||||
}
|
||||
CollectWitnessFlag = &cli.BoolFlag{
|
||||
Name: "collectwitness",
|
||||
Usage: "Enable state witness generation during block execution. Work in progress flag, don't use.",
|
||||
Category: flags.MiscCategory,
|
||||
}
|
||||
|
||||
// MISC settings
|
||||
SyncTargetFlag = &cli.StringFlag{
|
||||
|
|
@ -1760,6 +1765,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
|||
// TODO(fjl): force-enable this in --dev mode
|
||||
cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(CollectWitnessFlag.Name) {
|
||||
cfg.EnableWitnessCollection = ctx.Bool(CollectWitnessFlag.Name)
|
||||
}
|
||||
|
||||
if ctx.IsSet(RPCGlobalGasCapFlag.Name) {
|
||||
cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name)
|
||||
|
|
@ -2190,7 +2198,10 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
|||
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) {
|
||||
cache.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100
|
||||
}
|
||||
vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)}
|
||||
vmcfg := vm.Config{
|
||||
EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name),
|
||||
EnableWitnessCollection: ctx.Bool(CollectWitnessFlag.Name),
|
||||
}
|
||||
if ctx.IsSet(VMTraceFlag.Name) {
|
||||
if name := ctx.String(VMTraceFlag.Name); name != "" {
|
||||
var config json.RawMessage
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ func NewHexOrDecimal256(x int64) *HexOrDecimal256 {
|
|||
// It is similar to UnmarshalText, but allows parsing real decimals too, not just
|
||||
// quoted decimal strings.
|
||||
func (i *HexOrDecimal256) UnmarshalJSON(input []byte) error {
|
||||
if len(input) > 0 && input[0] == '"' {
|
||||
if len(input) > 1 && input[0] == '"' {
|
||||
input = input[1 : len(input)-1]
|
||||
}
|
||||
return i.UnmarshalText(input)
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ type HexOrDecimal64 uint64
|
|||
// It is similar to UnmarshalText, but allows parsing real decimals too, not just
|
||||
// quoted decimal strings.
|
||||
func (i *HexOrDecimal64) UnmarshalJSON(input []byte) error {
|
||||
if len(input) > 0 && input[0] == '"' {
|
||||
if len(input) > 1 && input[0] == '"' {
|
||||
input = input[1 : len(input)-1]
|
||||
}
|
||||
return i.UnmarshalText(input)
|
||||
|
|
|
|||
|
|
@ -468,7 +468,7 @@ func (d *Decimal) UnmarshalJSON(input []byte) error {
|
|||
if !isString(input) {
|
||||
return &json.UnmarshalTypeError{Value: "non-string", Type: reflect.TypeOf(uint64(0))}
|
||||
}
|
||||
if i, err := strconv.ParseInt(string(input[1:len(input)-1]), 10, 64); err == nil {
|
||||
if i, err := strconv.ParseUint(string(input[1:len(input)-1]), 10, 64); err == nil {
|
||||
*d = Decimal(i)
|
||||
return nil
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
|
@ -595,3 +596,29 @@ func BenchmarkPrettyDuration(b *testing.B) {
|
|||
}
|
||||
b.Logf("Post %s", a)
|
||||
}
|
||||
|
||||
func TestDecimalUnmarshalJSON(t *testing.T) {
|
||||
// These should error
|
||||
for _, tc := range []string{``, `"`, `""`, `"-1"`} {
|
||||
if err := new(Decimal).UnmarshalJSON([]byte(tc)); err == nil {
|
||||
t.Errorf("input %s should cause error", tc)
|
||||
}
|
||||
}
|
||||
// These should succeed
|
||||
for _, tc := range []struct {
|
||||
input string
|
||||
want uint64
|
||||
}{
|
||||
{`"0"`, 0},
|
||||
{`"9223372036854775807"`, math.MaxInt64},
|
||||
{`"18446744073709551615"`, math.MaxUint64},
|
||||
} {
|
||||
have := new(Decimal)
|
||||
if err := have.UnmarshalJSON([]byte(tc.input)); err != nil {
|
||||
t.Errorf("input %q triggered error: %v", tc.input, err)
|
||||
}
|
||||
if uint64(*have) != tc.want {
|
||||
t.Errorf("input %q, have %d want %d", tc.input, *have, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -562,12 +562,6 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
|
|||
return hash
|
||||
}
|
||||
|
||||
// Some weird constants to avoid constant memory allocs for them.
|
||||
var (
|
||||
u256_8 = uint256.NewInt(8)
|
||||
u256_32 = uint256.NewInt(32)
|
||||
)
|
||||
|
||||
// accumulateRewards credits the coinbase of the given block with the mining
|
||||
// reward. The total reward consists of the static block reward and rewards for
|
||||
// included uncles. The coinbase of each uncle block is also rewarded.
|
||||
|
|
@ -589,10 +583,10 @@ func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, heade
|
|||
r.AddUint64(uNum, 8)
|
||||
r.Sub(r, hNum)
|
||||
r.Mul(r, blockReward)
|
||||
r.Div(r, u256_8)
|
||||
r.Rsh(r, 3)
|
||||
stateDB.AddBalance(uncle.Coinbase, r, tracing.BalanceIncreaseRewardMineUncle)
|
||||
|
||||
r.Div(blockReward, u256_32)
|
||||
r.Rsh(blockReward, 5)
|
||||
reward.Add(reward, r)
|
||||
}
|
||||
stateDB.AddBalance(header.Coinbase, reward, tracing.BalanceIncreaseRewardMineBlock)
|
||||
|
|
|
|||
|
|
@ -20,8 +20,10 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
|
|
@ -34,14 +36,12 @@ import (
|
|||
type BlockValidator struct {
|
||||
config *params.ChainConfig // Chain configuration options
|
||||
bc *BlockChain // Canonical block chain
|
||||
engine consensus.Engine // Consensus engine used for validating
|
||||
}
|
||||
|
||||
// NewBlockValidator returns a new block validator which is safe for re-use
|
||||
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator {
|
||||
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain) *BlockValidator {
|
||||
validator := &BlockValidator{
|
||||
config: config,
|
||||
engine: engine,
|
||||
bc: blockchain,
|
||||
}
|
||||
return validator
|
||||
|
|
@ -59,7 +59,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
|||
// Header validity is known at this point. Here we verify that uncles, transactions
|
||||
// and withdrawals given in the block body match the header.
|
||||
header := block.Header()
|
||||
if err := v.engine.VerifyUncles(v.bc, block); err != nil {
|
||||
if err := v.bc.engine.VerifyUncles(v.bc, block); err != nil {
|
||||
return err
|
||||
}
|
||||
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
|
||||
|
|
@ -121,7 +121,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
|||
|
||||
// ValidateState validates the various changes that happen after a state transition,
|
||||
// such as amount of used gas, the receipt roots and the state root itself.
|
||||
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error {
|
||||
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error {
|
||||
header := block.Header()
|
||||
if block.GasUsed() != usedGas {
|
||||
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
|
||||
|
|
@ -132,6 +132,11 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||
if rbloom != header.Bloom {
|
||||
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
||||
}
|
||||
// In stateless mode, return early because the receipt and state root are not
|
||||
// provided through the witness, rather the cross validator needs to return it.
|
||||
if stateless {
|
||||
return nil
|
||||
}
|
||||
// The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
|
||||
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
|
||||
if receiptSha != header.ReceiptHash {
|
||||
|
|
@ -145,6 +150,28 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||
return nil
|
||||
}
|
||||
|
||||
// ValidateWitness cross validates a block execution with stateless remote clients.
|
||||
//
|
||||
// Normally we'd distribute the block witness to remote cross validators, wait
|
||||
// for them to respond and then merge the results. For now, however, it's only
|
||||
// Geth, so do an internal stateless run.
|
||||
func (v *BlockValidator) ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error {
|
||||
// Run the cross client stateless execution
|
||||
// TODO(karalabe): Self-stateless for now, swap with other clients
|
||||
crossReceiptRoot, crossStateRoot, err := ExecuteStateless(v.config, witness)
|
||||
if err != nil {
|
||||
return fmt.Errorf("stateless execution failed: %v", err)
|
||||
}
|
||||
// Stateless cross execution suceeeded, validate the withheld computed fields
|
||||
if crossReceiptRoot != receiptRoot {
|
||||
return fmt.Errorf("cross validator receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, receiptRoot)
|
||||
}
|
||||
if crossStateRoot != stateRoot {
|
||||
return fmt.Errorf("cross validator state root mismatch (cross: %x local: %x)", crossStateRoot, stateRoot)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CalcGasLimit computes the gas limit of the next block after parent. It aims
|
||||
// to keep the baseline gas close to the provided target, and increase it towards
|
||||
// the target if the baseline gas is lower.
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
|
|
@ -302,18 +303,18 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||
vmConfig: vmConfig,
|
||||
logger: vmConfig.Tracer,
|
||||
}
|
||||
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
|
||||
bc.forker = NewForkChoice(bc, shouldPreserve)
|
||||
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
|
||||
bc.validator = NewBlockValidator(chainConfig, bc, engine)
|
||||
bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine)
|
||||
bc.processor = NewStateProcessor(chainConfig, bc, engine)
|
||||
|
||||
var err error
|
||||
bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.insertStopped)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
|
||||
bc.forker = NewForkChoice(bc, shouldPreserve)
|
||||
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
|
||||
bc.validator = NewBlockValidator(chainConfig, bc)
|
||||
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
|
||||
bc.processor = NewStateProcessor(chainConfig, bc.hc)
|
||||
|
||||
bc.genesisBlock = bc.GetBlockByNumber(0)
|
||||
if bc.genesisBlock == nil {
|
||||
return nil, ErrNoGenesis
|
||||
|
|
@ -1809,7 +1810,14 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
// while processing transactions. Before Byzantium the prefetcher is mostly
|
||||
// useless due to the intermediate root hashing after each transaction.
|
||||
if bc.chainConfig.IsByzantium(block.Number()) {
|
||||
statedb.StartPrefetcher("chain")
|
||||
var witness *stateless.Witness
|
||||
if bc.vmConfig.EnableWitnessCollection {
|
||||
witness, err = stateless.NewWitness(bc, block)
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
}
|
||||
}
|
||||
statedb.StartPrefetcher("chain", witness)
|
||||
}
|
||||
activeState = statedb
|
||||
|
||||
|
|
@ -1924,11 +1932,18 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
|||
ptime := time.Since(pstart)
|
||||
|
||||
vstart := time.Now()
|
||||
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
|
||||
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil {
|
||||
bc.reportBlock(block, receipts, err)
|
||||
return nil, err
|
||||
}
|
||||
vtime := time.Since(vstart)
|
||||
|
||||
if witness := statedb.Witness(); witness != nil {
|
||||
if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil {
|
||||
bc.reportBlock(block, receipts, err)
|
||||
return nil, fmt.Errorf("cross verification failed: %v", err)
|
||||
}
|
||||
}
|
||||
proctime := time.Since(start) // processing + validation
|
||||
|
||||
// Update the metrics touched during block processing and validation
|
||||
|
|
|
|||
|
|
@ -168,8 +168,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
|||
blockchain.reportBlock(block, receipts, err)
|
||||
return err
|
||||
}
|
||||
err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas)
|
||||
if err != nil {
|
||||
if err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil {
|
||||
blockchain.reportBlock(block, receipts, err)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -594,7 +594,7 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
|||
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
|
||||
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
|
||||
// Pre-deploy EIP-4788 system contract
|
||||
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode},
|
||||
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
||||
},
|
||||
}
|
||||
if faucet != nil {
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@ import (
|
|||
)
|
||||
|
||||
func TestReadWriteFreezerTableMeta(t *testing.T) {
|
||||
f, err := os.CreateTemp(os.TempDir(), "*")
|
||||
f, err := os.CreateTemp(t.TempDir(), "*")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create file %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
err = writeMetadata(f, newMetadata(100))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write metadata %v", err)
|
||||
|
|
@ -43,10 +44,11 @@ func TestReadWriteFreezerTableMeta(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInitializeFreezerTableMeta(t *testing.T) {
|
||||
f, err := os.CreateTemp(os.TempDir(), "*")
|
||||
f, err := os.CreateTemp(t.TempDir(), "*")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create file %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
meta, err := loadMetadata(f, uint64(100))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read metadata %v", err)
|
||||
|
|
|
|||
|
|
@ -147,9 +147,9 @@ func (t *table) NewIterator(prefix []byte, start []byte) ethdb.Iterator {
|
|||
}
|
||||
}
|
||||
|
||||
// Stat returns a particular internal stat of the database.
|
||||
func (t *table) Stat(property string) (string, error) {
|
||||
return t.db.Stat(property)
|
||||
// Stat returns the statistic data of the database.
|
||||
func (t *table) Stat() (string, error) {
|
||||
return t.db.Stat()
|
||||
}
|
||||
|
||||
// Compact flattens the underlying data store for the given key range. In essence,
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ func TestAccountHeaderGas(t *testing.T) {
|
|||
|
||||
// Check cold read cost
|
||||
gas := ae.VersionGas(testAddr, false)
|
||||
if gas != params.WitnessBranchReadCost+params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessChunkReadCost)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
|
|
@ -71,8 +71,8 @@ func TestAccountHeaderGas(t *testing.T) {
|
|||
|
||||
// Check cold write cost
|
||||
gas = ae.VersionGas(testAddr, true)
|
||||
if gas != params.WitnessBranchWriteCost+params.WitnessChunkWriteCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessBranchWriteCost)
|
||||
if want := params.WitnessBranchWriteCost + params.WitnessChunkWriteCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm write cost
|
||||
|
|
@ -83,8 +83,8 @@ func TestAccountHeaderGas(t *testing.T) {
|
|||
|
||||
// Check a write without a read charges both read and write costs
|
||||
gas = ae.BalanceGas(testAddr2, true)
|
||||
if gas != params.WitnessBranchReadCost+params.WitnessBranchWriteCost+params.WitnessChunkWriteCost+params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessBranchWriteCost+params.WitnessChunkWriteCost+params.WitnessChunkReadCost)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessBranchWriteCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check that a write followed by a read charges nothing
|
||||
|
|
@ -113,8 +113,8 @@ func TestContractCreateInitGas(t *testing.T) {
|
|||
|
||||
// Check cold read cost, without a value
|
||||
gas := ae.ContractCreateInitGas(testAddr, false)
|
||||
if gas != params.WitnessBranchWriteCost+params.WitnessBranchReadCost+params.WitnessChunkWriteCost*2+params.WitnessChunkReadCost*2 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchWriteCost+params.WitnessBranchReadCost+params.WitnessChunkWriteCost*3)
|
||||
if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost*2 + params.WitnessChunkReadCost*2; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
|
|
@ -131,8 +131,8 @@ func TestMessageCallGas(t *testing.T) {
|
|||
|
||||
// Check cold read cost, without a value
|
||||
gas := ae.MessageCallGas(testAddr)
|
||||
if gas != params.WitnessBranchReadCost+params.WitnessChunkReadCost*2 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessChunkReadCost*2)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost*2; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check that reading the version and code size of the same account does not incur the branch read cost
|
||||
|
|
|
|||
|
|
@ -60,11 +60,11 @@ func newAccessList() *accessList {
|
|||
}
|
||||
|
||||
// Copy creates an independent copy of an accessList.
|
||||
func (a *accessList) Copy() *accessList {
|
||||
func (al *accessList) Copy() *accessList {
|
||||
cp := newAccessList()
|
||||
cp.addresses = maps.Clone(a.addresses)
|
||||
cp.slots = make([]map[common.Hash]struct{}, len(a.slots))
|
||||
for i, slotMap := range a.slots {
|
||||
cp.addresses = maps.Clone(al.addresses)
|
||||
cp.slots = make([]map[common.Hash]struct{}, len(al.slots))
|
||||
for i, slotMap := range al.slots {
|
||||
cp.slots[i] = maps.Clone(slotMap)
|
||||
}
|
||||
return cp
|
||||
|
|
|
|||
|
|
@ -123,7 +123,11 @@ type Trie interface {
|
|||
// The returned nodeset can be nil if the trie is clean(nothing to commit).
|
||||
// Once the trie is committed, it's not usable anymore. A new trie must
|
||||
// be created with new root and updated trie database for following usage
|
||||
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
|
||||
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet)
|
||||
|
||||
// Witness returns a set containing all trie nodes that have been accessed.
|
||||
// The returned map could be nil if the witness is empty.
|
||||
Witness() map[string]struct{}
|
||||
|
||||
// NodeIterator returns an iterator that returns nodes of the trie. Iteration
|
||||
// starts at the key after the given start key. And error will be returned
|
||||
|
|
|
|||
|
|
@ -360,10 +360,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi
|
|||
for i, key := range result.keys {
|
||||
snapTrie.Update(key, result.vals[i])
|
||||
}
|
||||
root, nodes, err := snapTrie.Commit(false)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
root, nodes := snapTrie.Commit(false)
|
||||
if nodes != nil {
|
||||
tdb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
tdb.Commit(root, false)
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st
|
|||
if !commit {
|
||||
return stTrie.Hash()
|
||||
}
|
||||
root, nodes, _ := stTrie.Commit(false)
|
||||
root, nodes := stTrie.Commit(false)
|
||||
if nodes != nil {
|
||||
t.nodes.Merge(nodes)
|
||||
}
|
||||
|
|
@ -218,7 +218,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st
|
|||
}
|
||||
|
||||
func (t *testHelper) Commit() common.Hash {
|
||||
root, nodes, _ := t.accTrie.Commit(true)
|
||||
root, nodes := t.accTrie.Commit(true)
|
||||
if nodes != nil {
|
||||
t.nodes.Merge(nodes)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -815,7 +815,7 @@ func TestStorageIteratorDeletions(t *testing.T) {
|
|||
verifyIterator(t, 2, snaps.Snapshot(common.HexToHash("0x06")).(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa")), verifyStorage)
|
||||
}
|
||||
|
||||
// BenchmarkAccountIteratorTraversal is a bit a bit notorious -- all layers contain the
|
||||
// BenchmarkAccountIteratorTraversal is a bit notorious -- all layers contain the
|
||||
// exact same 200 accounts. That means that we need to process 2000 items, but
|
||||
// only spit out 200 values eventually.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -666,6 +666,9 @@ func diffToDisk(bottom *diffLayer) *diskLayer {
|
|||
|
||||
// Release releases resources
|
||||
func (t *Tree) Release() {
|
||||
t.lock.RLock()
|
||||
defer t.lock.RUnlock()
|
||||
|
||||
if dl := t.disklayer(); dl != nil {
|
||||
dl.Release()
|
||||
}
|
||||
|
|
@ -829,6 +832,8 @@ func (t *Tree) disklayer() *diskLayer {
|
|||
case *diskLayer:
|
||||
return layer
|
||||
case *diffLayer:
|
||||
layer.lock.RLock()
|
||||
defer layer.lock.RUnlock()
|
||||
return layer.origin
|
||||
default:
|
||||
panic(fmt.Sprintf("%T: undefined layer", snap))
|
||||
|
|
@ -848,8 +853,8 @@ func (t *Tree) diskRoot() common.Hash {
|
|||
// generating is an internal helper function which reports whether the snapshot
|
||||
// is still under the construction.
|
||||
func (t *Tree) generating() (bool, error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
t.lock.RLock()
|
||||
defer t.lock.RUnlock()
|
||||
|
||||
layer := t.disklayer()
|
||||
if layer == nil {
|
||||
|
|
@ -860,10 +865,10 @@ func (t *Tree) generating() (bool, error) {
|
|||
return layer.genMarker != nil, nil
|
||||
}
|
||||
|
||||
// DiskRoot is a external helper function to return the disk layer root.
|
||||
// DiskRoot is an external helper function to return the disk layer root.
|
||||
func (t *Tree) DiskRoot() common.Hash {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
t.lock.RLock()
|
||||
defer t.lock.RUnlock()
|
||||
|
||||
return t.diskRoot()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -230,6 +230,14 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
|
|||
}
|
||||
value.SetBytes(val)
|
||||
}
|
||||
// Independent of where we loaded the data from, add it to the prefetcher.
|
||||
// Whilst this would be a bit weird if snapshots are disabled, but we still
|
||||
// want the trie nodes to end up in the prefetcher too, so just push through.
|
||||
if s.db.prefetcher != nil && s.data.Root != types.EmptyRootHash {
|
||||
if err = s.db.prefetcher.prefetch(s.addrHash, s.origin.Root, s.address, [][]byte{key[:]}, true); err != nil {
|
||||
log.Error("Failed to prefetch storage slot", "addr", s.address, "key", key, "err", err)
|
||||
}
|
||||
}
|
||||
s.originStorage[key] = value
|
||||
return value
|
||||
}
|
||||
|
|
@ -293,7 +301,7 @@ func (s *stateObject) finalise() {
|
|||
s.pendingStorage[key] = value
|
||||
}
|
||||
if s.db.prefetcher != nil && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash {
|
||||
if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch); err != nil {
|
||||
if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch, false); err != nil {
|
||||
log.Error("Failed to prefetch slots", "addr", s.address, "slots", len(slotsToPrefetch), "err", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -315,11 +323,17 @@ func (s *stateObject) finalise() {
|
|||
//
|
||||
// It assumes all the dirty storage slots have been finalized before.
|
||||
func (s *stateObject) updateTrie() (Trie, error) {
|
||||
// Short circuit if nothing changed, don't bother with hashing anything
|
||||
// Short circuit if nothing was accessed, don't trigger a prefetcher warning
|
||||
if len(s.uncommittedStorage) == 0 {
|
||||
return s.trie, nil
|
||||
// Nothing was written, so we could stop early. Unless we have both reads
|
||||
// and witness collection enabled, in which case we need to fetch the trie.
|
||||
if s.db.witness == nil || len(s.originStorage) == 0 {
|
||||
return s.trie, nil
|
||||
}
|
||||
}
|
||||
// Retrieve a pretecher populated trie, or fall back to the database
|
||||
// Retrieve a pretecher populated trie, or fall back to the database. This will
|
||||
// block until all prefetch tasks are done, which are needed for witnesses even
|
||||
// for unmodified state objects.
|
||||
tr := s.getPrefetchedTrie()
|
||||
if tr != nil {
|
||||
// Prefetcher returned a live trie, swap it out for the current one
|
||||
|
|
@ -333,6 +347,10 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
// Short circuit if nothing changed, don't bother with hashing anything
|
||||
if len(s.uncommittedStorage) == 0 {
|
||||
return s.trie, nil
|
||||
}
|
||||
// Perform trie updates before deletions. This prevents resolution of unnecessary trie nodes
|
||||
// in circumstances similar to the following:
|
||||
//
|
||||
|
|
@ -462,10 +480,7 @@ func (s *stateObject) commit() (*accountUpdate, *trienode.NodeSet, error) {
|
|||
s.origin = s.data.Copy()
|
||||
return op, nil, nil
|
||||
}
|
||||
root, nodes, err := s.trie.Commit(false)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root, nodes := s.trie.Commit(false)
|
||||
s.data.Root = root
|
||||
s.origin = s.data.Copy()
|
||||
return op, nodes, nil
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -105,7 +106,7 @@ type StateDB struct {
|
|||
// resurrection. The account value is tracked as the original value
|
||||
// before the transition. This map is populated at the transaction
|
||||
// boundaries.
|
||||
stateObjectsDestruct map[common.Address]*types.StateAccount
|
||||
stateObjectsDestruct map[common.Address]*stateObject
|
||||
|
||||
// This map tracks the account mutations that occurred during the
|
||||
// transition. Uncommitted mutations belonging to the same account
|
||||
|
|
@ -146,6 +147,9 @@ type StateDB struct {
|
|||
validRevisions []revision
|
||||
nextRevisionId int
|
||||
|
||||
// State witness if cross validation is needed
|
||||
witness *stateless.Witness
|
||||
|
||||
// Measurements gathered during execution for debugging purposes
|
||||
AccountReads time.Duration
|
||||
AccountHashes time.Duration
|
||||
|
|
@ -177,7 +181,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
|
|||
originalRoot: root,
|
||||
snaps: snaps,
|
||||
stateObjects: make(map[common.Address]*stateObject),
|
||||
stateObjectsDestruct: make(map[common.Address]*types.StateAccount),
|
||||
stateObjectsDestruct: make(map[common.Address]*stateObject),
|
||||
mutations: make(map[common.Address]*mutation),
|
||||
logs: make(map[common.Hash][]*types.Log),
|
||||
preimages: make(map[common.Hash][]byte),
|
||||
|
|
@ -200,14 +204,19 @@ func (s *StateDB) SetLogger(l *tracing.Hooks) {
|
|||
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
|
||||
// state trie concurrently while the state is mutated so that when we reach the
|
||||
// commit phase, most of the needed data is already hot.
|
||||
func (s *StateDB) StartPrefetcher(namespace string) {
|
||||
func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness) {
|
||||
// Terminate any previously running prefetcher
|
||||
if s.prefetcher != nil {
|
||||
s.prefetcher.terminate(false)
|
||||
s.prefetcher.report()
|
||||
s.prefetcher = nil
|
||||
}
|
||||
// Enable witness collection if requested
|
||||
s.witness = witness
|
||||
|
||||
// If snapshots are enabled, start prefethers explicitly
|
||||
if s.snap != nil {
|
||||
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace)
|
||||
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, witness == nil)
|
||||
|
||||
// With the switch to the Proof-of-Stake consensus algorithm, block production
|
||||
// rewards are now handled at the consensus layer. Consequently, a block may
|
||||
|
|
@ -218,7 +227,7 @@ func (s *StateDB) StartPrefetcher(namespace string) {
|
|||
// To prevent this, the account trie is always scheduled for prefetching once
|
||||
// the prefetcher is constructed. For more details, see:
|
||||
// https://github.com/ethereum/go-ethereum/issues/29880
|
||||
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil); err != nil {
|
||||
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil, false); err != nil {
|
||||
log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -586,7 +595,6 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
|
|||
start := time.Now()
|
||||
acc, err := s.snap.Account(crypto.HashData(s.hasher, addr.Bytes()))
|
||||
s.SnapshotAccountReads += time.Since(start)
|
||||
|
||||
if err == nil {
|
||||
if acc == nil {
|
||||
return nil
|
||||
|
|
@ -620,6 +628,14 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
// Independent of where we loaded the data from, add it to the prefetcher.
|
||||
// Whilst this would be a bit weird if snapshots are disabled, but we still
|
||||
// want the trie nodes to end up in the prefetcher too, so just push through.
|
||||
if s.prefetcher != nil {
|
||||
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, [][]byte{addr[:]}, true); err != nil {
|
||||
log.Error("Failed to prefetch account", "addr", addr, "err", err)
|
||||
}
|
||||
}
|
||||
// Insert into the live set
|
||||
obj := newObject(s, addr, data)
|
||||
s.setStateObject(obj)
|
||||
|
|
@ -679,7 +695,7 @@ func (s *StateDB) Copy() *StateDB {
|
|||
hasher: crypto.NewKeccakState(),
|
||||
originalRoot: s.originalRoot,
|
||||
stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)),
|
||||
stateObjectsDestruct: maps.Clone(s.stateObjectsDestruct),
|
||||
stateObjectsDestruct: make(map[common.Address]*stateObject, len(s.stateObjectsDestruct)),
|
||||
mutations: make(map[common.Address]*mutation, len(s.mutations)),
|
||||
dbErr: s.dbErr,
|
||||
refund: s.refund,
|
||||
|
|
@ -699,10 +715,17 @@ func (s *StateDB) Copy() *StateDB {
|
|||
snaps: s.snaps,
|
||||
snap: s.snap,
|
||||
}
|
||||
if s.witness != nil {
|
||||
state.witness = s.witness.Copy()
|
||||
}
|
||||
// Deep copy cached state objects.
|
||||
for addr, obj := range s.stateObjects {
|
||||
state.stateObjects[addr] = obj.deepCopy(state)
|
||||
}
|
||||
// Deep copy destructed state objects.
|
||||
for addr, obj := range s.stateObjectsDestruct {
|
||||
state.stateObjectsDestruct[addr] = obj.deepCopy(state)
|
||||
}
|
||||
// Deep copy the object state markers.
|
||||
for addr, op := range s.mutations {
|
||||
state.mutations[addr] = op.copy()
|
||||
|
|
@ -784,7 +807,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
|||
// set indefinitely). Note only the first occurred self-destruct
|
||||
// event is tracked.
|
||||
if _, ok := s.stateObjectsDestruct[obj.address]; !ok {
|
||||
s.stateObjectsDestruct[obj.address] = obj.origin
|
||||
s.stateObjectsDestruct[obj.address] = obj
|
||||
}
|
||||
} else {
|
||||
obj.finalise()
|
||||
|
|
@ -796,7 +819,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
|||
addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure
|
||||
}
|
||||
if s.prefetcher != nil && len(addressesToPrefetch) > 0 {
|
||||
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch); err != nil {
|
||||
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch, false); err != nil {
|
||||
log.Error("Failed to prefetch addresses", "addresses", len(addressesToPrefetch), "err", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -842,18 +865,58 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
|||
obj := s.stateObjects[addr] // closure for the task runner below
|
||||
workers.Go(func() error {
|
||||
obj.updateRoot()
|
||||
|
||||
// If witness building is enabled and the state object has a trie,
|
||||
// gather the witnesses for its specific storage trie
|
||||
if s.witness != nil && obj.trie != nil {
|
||||
s.witness.AddState(obj.trie.Witness())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
// If witness building is enabled, gather all the read-only accesses
|
||||
if s.witness != nil {
|
||||
// Pull in anything that has been accessed before destruction
|
||||
for _, obj := range s.stateObjectsDestruct {
|
||||
// Skip any objects that haven't touched their storage
|
||||
if len(obj.originStorage) == 0 {
|
||||
continue
|
||||
}
|
||||
if trie := obj.getPrefetchedTrie(); trie != nil {
|
||||
s.witness.AddState(trie.Witness())
|
||||
} else if obj.trie != nil {
|
||||
s.witness.AddState(obj.trie.Witness())
|
||||
}
|
||||
}
|
||||
// Pull in only-read and non-destructed trie witnesses
|
||||
for _, obj := range s.stateObjects {
|
||||
// Skip any objects that have been updated
|
||||
if _, ok := s.mutations[obj.address]; ok {
|
||||
continue
|
||||
}
|
||||
// Skip any objects that haven't touched their storage
|
||||
if len(obj.originStorage) == 0 {
|
||||
continue
|
||||
}
|
||||
if trie := obj.getPrefetchedTrie(); trie != nil {
|
||||
s.witness.AddState(trie.Witness())
|
||||
} else if obj.trie != nil {
|
||||
s.witness.AddState(obj.trie.Witness())
|
||||
}
|
||||
}
|
||||
}
|
||||
workers.Wait()
|
||||
s.StorageUpdates += time.Since(start)
|
||||
|
||||
// Now we're about to start to write changes to the trie. The trie is so far
|
||||
// _untouched_. We can check with the prefetcher, if it can give us a trie
|
||||
// which has the same root, but also has some content loaded into it.
|
||||
//
|
||||
// Don't check prefetcher if verkle trie has been used. In the context of verkle,
|
||||
// only a single trie is used for state hashing. Replacing a non-nil verkle tree
|
||||
// here could result in losing uncommitted changes from storage.
|
||||
start = time.Now()
|
||||
|
||||
if s.prefetcher != nil {
|
||||
if s.prefetcher != nil && (s.trie == nil || !s.trie.IsVerkle()) {
|
||||
if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil {
|
||||
log.Error("Failed to retrieve account pre-fetcher trie")
|
||||
} else {
|
||||
|
|
@ -900,7 +963,13 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
|||
// Track the amount of time wasted on hashing the account trie
|
||||
defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now())
|
||||
|
||||
return s.trie.Hash()
|
||||
hash := s.trie.Hash()
|
||||
|
||||
// If witness building is enabled, gather the account trie witness
|
||||
if s.witness != nil {
|
||||
s.witness.AddState(s.trie.Witness())
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// SetTxContext sets the current transaction hash and index which are
|
||||
|
|
@ -1056,7 +1125,9 @@ func (s *StateDB) handleDestruction() (map[common.Hash]*accountDelete, []*trieno
|
|||
buf = crypto.NewKeccakState()
|
||||
deletes = make(map[common.Hash]*accountDelete)
|
||||
)
|
||||
for addr, prev := range s.stateObjectsDestruct {
|
||||
for addr, prevObj := range s.stateObjectsDestruct {
|
||||
prev := prevObj.origin
|
||||
|
||||
// The account was non-existent, and it's marked as destructed in the scope
|
||||
// of block. It can be either case (a) or (b) and will be interpreted as
|
||||
// null->null state transition.
|
||||
|
|
@ -1175,10 +1246,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) {
|
|||
// code didn't anticipate for.
|
||||
workers.Go(func() error {
|
||||
// Write the account trie changes, measuring the amount of wasted time
|
||||
newroot, set, err := s.trie.Commit(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newroot, set := s.trie.Commit(true)
|
||||
root = newroot
|
||||
|
||||
if err := merge(set); err != nil {
|
||||
|
|
@ -1238,7 +1306,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) {
|
|||
|
||||
// Clear all internal flags and update state root at the end.
|
||||
s.mutations = make(map[common.Address]*mutation)
|
||||
s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount)
|
||||
s.stateObjectsDestruct = make(map[common.Address]*stateObject)
|
||||
|
||||
origin := s.originalRoot
|
||||
s.originalRoot = root
|
||||
|
|
@ -1411,3 +1479,8 @@ func (s *StateDB) markUpdate(addr common.Address) {
|
|||
func (s *StateDB) PointCache() *utils.PointCache {
|
||||
return s.db.PointCache()
|
||||
}
|
||||
|
||||
// Witness retrieves the current state witness being collected.
|
||||
func (s *StateDB) Witness() *stateless.Witness {
|
||||
return s.witness
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,31 +44,49 @@ type triePrefetcher struct {
|
|||
root common.Hash // Root hash of the account trie for metrics
|
||||
fetchers map[string]*subfetcher // Subfetchers for each trie
|
||||
term chan struct{} // Channel to signal interruption
|
||||
noreads bool // Whether to ignore state-read-only prefetch requests
|
||||
|
||||
deliveryMissMeter metrics.Meter
|
||||
accountLoadMeter metrics.Meter
|
||||
accountDupMeter metrics.Meter
|
||||
accountWasteMeter metrics.Meter
|
||||
storageLoadMeter metrics.Meter
|
||||
storageDupMeter metrics.Meter
|
||||
storageWasteMeter metrics.Meter
|
||||
|
||||
accountLoadReadMeter metrics.Meter
|
||||
accountLoadWriteMeter metrics.Meter
|
||||
accountDupReadMeter metrics.Meter
|
||||
accountDupWriteMeter metrics.Meter
|
||||
accountDupCrossMeter metrics.Meter
|
||||
accountWasteMeter metrics.Meter
|
||||
|
||||
storageLoadReadMeter metrics.Meter
|
||||
storageLoadWriteMeter metrics.Meter
|
||||
storageDupReadMeter metrics.Meter
|
||||
storageDupWriteMeter metrics.Meter
|
||||
storageDupCrossMeter metrics.Meter
|
||||
storageWasteMeter metrics.Meter
|
||||
}
|
||||
|
||||
func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePrefetcher {
|
||||
func newTriePrefetcher(db Database, root common.Hash, namespace string, noreads bool) *triePrefetcher {
|
||||
prefix := triePrefetchMetricsPrefix + namespace
|
||||
return &triePrefetcher{
|
||||
db: db,
|
||||
root: root,
|
||||
fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map
|
||||
term: make(chan struct{}),
|
||||
noreads: noreads,
|
||||
|
||||
deliveryMissMeter: metrics.GetOrRegisterMeter(prefix+"/deliverymiss", nil),
|
||||
accountLoadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load", nil),
|
||||
accountDupMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup", nil),
|
||||
accountWasteMeter: metrics.GetOrRegisterMeter(prefix+"/account/waste", nil),
|
||||
storageLoadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load", nil),
|
||||
storageDupMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup", nil),
|
||||
storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil),
|
||||
|
||||
accountLoadReadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load/read", nil),
|
||||
accountLoadWriteMeter: metrics.GetOrRegisterMeter(prefix+"/account/load/write", nil),
|
||||
accountDupReadMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/read", nil),
|
||||
accountDupWriteMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/write", nil),
|
||||
accountDupCrossMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/cross", nil),
|
||||
accountWasteMeter: metrics.GetOrRegisterMeter(prefix+"/account/waste", nil),
|
||||
|
||||
storageLoadReadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load/read", nil),
|
||||
storageLoadWriteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load/write", nil),
|
||||
storageDupReadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/read", nil),
|
||||
storageDupWriteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/write", nil),
|
||||
storageDupCrossMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/cross", nil),
|
||||
storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,19 +116,31 @@ func (p *triePrefetcher) report() {
|
|||
fetcher.wait() // ensure the fetcher's idle before poking in its internals
|
||||
|
||||
if fetcher.root == p.root {
|
||||
p.accountLoadMeter.Mark(int64(len(fetcher.seen)))
|
||||
p.accountDupMeter.Mark(int64(fetcher.dups))
|
||||
p.accountLoadReadMeter.Mark(int64(len(fetcher.seenRead)))
|
||||
p.accountLoadWriteMeter.Mark(int64(len(fetcher.seenWrite)))
|
||||
|
||||
p.accountDupReadMeter.Mark(int64(fetcher.dupsRead))
|
||||
p.accountDupWriteMeter.Mark(int64(fetcher.dupsWrite))
|
||||
p.accountDupCrossMeter.Mark(int64(fetcher.dupsCross))
|
||||
|
||||
for _, key := range fetcher.used {
|
||||
delete(fetcher.seen, string(key))
|
||||
delete(fetcher.seenRead, string(key))
|
||||
delete(fetcher.seenWrite, string(key))
|
||||
}
|
||||
p.accountWasteMeter.Mark(int64(len(fetcher.seen)))
|
||||
p.accountWasteMeter.Mark(int64(len(fetcher.seenRead) + len(fetcher.seenWrite)))
|
||||
} else {
|
||||
p.storageLoadMeter.Mark(int64(len(fetcher.seen)))
|
||||
p.storageDupMeter.Mark(int64(fetcher.dups))
|
||||
p.storageLoadReadMeter.Mark(int64(len(fetcher.seenRead)))
|
||||
p.storageLoadWriteMeter.Mark(int64(len(fetcher.seenWrite)))
|
||||
|
||||
p.storageDupReadMeter.Mark(int64(fetcher.dupsRead))
|
||||
p.storageDupWriteMeter.Mark(int64(fetcher.dupsWrite))
|
||||
p.storageDupCrossMeter.Mark(int64(fetcher.dupsCross))
|
||||
|
||||
for _, key := range fetcher.used {
|
||||
delete(fetcher.seen, string(key))
|
||||
delete(fetcher.seenRead, string(key))
|
||||
delete(fetcher.seenWrite, string(key))
|
||||
}
|
||||
p.storageWasteMeter.Mark(int64(len(fetcher.seen)))
|
||||
p.storageWasteMeter.Mark(int64(len(fetcher.seenRead) + len(fetcher.seenWrite)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -126,7 +156,11 @@ func (p *triePrefetcher) report() {
|
|||
// upon the same contract, the parameters invoking this method may be
|
||||
// repeated.
|
||||
// 2. Finalize of the main account trie. This happens only once per block.
|
||||
func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) error {
|
||||
func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte, read bool) error {
|
||||
// If the state item is only being read, but reads are disabled, return
|
||||
if read && p.noreads {
|
||||
return nil
|
||||
}
|
||||
// Ensure the subfetcher is still alive
|
||||
select {
|
||||
case <-p.term:
|
||||
|
|
@ -139,7 +173,7 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr comm
|
|||
fetcher = newSubfetcher(p.db, p.root, owner, root, addr)
|
||||
p.fetchers[id] = fetcher
|
||||
}
|
||||
return fetcher.schedule(keys)
|
||||
return fetcher.schedule(keys, read)
|
||||
}
|
||||
|
||||
// trie returns the trie matching the root hash, blocking until the fetcher of
|
||||
|
|
@ -186,38 +220,51 @@ type subfetcher struct {
|
|||
addr common.Address // Address of the account that the trie belongs to
|
||||
trie Trie // Trie being populated with nodes
|
||||
|
||||
tasks [][]byte // Items queued up for retrieval
|
||||
lock sync.Mutex // Lock protecting the task queue
|
||||
tasks []*subfetcherTask // Items queued up for retrieval
|
||||
lock sync.Mutex // Lock protecting the task queue
|
||||
|
||||
wake chan struct{} // Wake channel if a new task is scheduled
|
||||
stop chan struct{} // Channel to interrupt processing
|
||||
term chan struct{} // Channel to signal interruption
|
||||
|
||||
seen map[string]struct{} // Tracks the entries already loaded
|
||||
dups int // Number of duplicate preload tasks
|
||||
used [][]byte // Tracks the entries used in the end
|
||||
seenRead map[string]struct{} // Tracks the entries already loaded via read operations
|
||||
seenWrite map[string]struct{} // Tracks the entries already loaded via write operations
|
||||
|
||||
dupsRead int // Number of duplicate preload tasks via reads only
|
||||
dupsWrite int // Number of duplicate preload tasks via writes only
|
||||
dupsCross int // Number of duplicate preload tasks via read-write-crosses
|
||||
|
||||
used [][]byte // Tracks the entries used in the end
|
||||
}
|
||||
|
||||
// subfetcherTask is a trie path to prefetch, tagged with whether it originates
|
||||
// from a read or a write request.
|
||||
type subfetcherTask struct {
|
||||
read bool
|
||||
key []byte
|
||||
}
|
||||
|
||||
// newSubfetcher creates a goroutine to prefetch state items belonging to a
|
||||
// particular root hash.
|
||||
func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash, addr common.Address) *subfetcher {
|
||||
sf := &subfetcher{
|
||||
db: db,
|
||||
state: state,
|
||||
owner: owner,
|
||||
root: root,
|
||||
addr: addr,
|
||||
wake: make(chan struct{}, 1),
|
||||
stop: make(chan struct{}),
|
||||
term: make(chan struct{}),
|
||||
seen: make(map[string]struct{}),
|
||||
db: db,
|
||||
state: state,
|
||||
owner: owner,
|
||||
root: root,
|
||||
addr: addr,
|
||||
wake: make(chan struct{}, 1),
|
||||
stop: make(chan struct{}),
|
||||
term: make(chan struct{}),
|
||||
seenRead: make(map[string]struct{}),
|
||||
seenWrite: make(map[string]struct{}),
|
||||
}
|
||||
go sf.loop()
|
||||
return sf
|
||||
}
|
||||
|
||||
// schedule adds a batch of trie keys to the queue to prefetch.
|
||||
func (sf *subfetcher) schedule(keys [][]byte) error {
|
||||
func (sf *subfetcher) schedule(keys [][]byte, read bool) error {
|
||||
// Ensure the subfetcher is still alive
|
||||
select {
|
||||
case <-sf.term:
|
||||
|
|
@ -226,7 +273,10 @@ func (sf *subfetcher) schedule(keys [][]byte) error {
|
|||
}
|
||||
// Append the tasks to the current queue
|
||||
sf.lock.Lock()
|
||||
sf.tasks = append(sf.tasks, keys...)
|
||||
for _, key := range keys {
|
||||
key := key // closure for the append below
|
||||
sf.tasks = append(sf.tasks, &subfetcherTask{read: read, key: key})
|
||||
}
|
||||
sf.lock.Unlock()
|
||||
|
||||
// Notify the background thread to execute scheduled tasks
|
||||
|
|
@ -303,16 +353,36 @@ func (sf *subfetcher) loop() {
|
|||
sf.lock.Unlock()
|
||||
|
||||
for _, task := range tasks {
|
||||
if _, ok := sf.seen[string(task)]; ok {
|
||||
sf.dups++
|
||||
continue
|
||||
}
|
||||
if len(task) == common.AddressLength {
|
||||
sf.trie.GetAccount(common.BytesToAddress(task))
|
||||
key := string(task.key)
|
||||
if task.read {
|
||||
if _, ok := sf.seenRead[key]; ok {
|
||||
sf.dupsRead++
|
||||
continue
|
||||
}
|
||||
if _, ok := sf.seenWrite[key]; ok {
|
||||
sf.dupsCross++
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
sf.trie.GetStorage(sf.addr, task)
|
||||
if _, ok := sf.seenRead[key]; ok {
|
||||
sf.dupsCross++
|
||||
continue
|
||||
}
|
||||
if _, ok := sf.seenWrite[key]; ok {
|
||||
sf.dupsWrite++
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(task.key) == common.AddressLength {
|
||||
sf.trie.GetAccount(common.BytesToAddress(task.key))
|
||||
} else {
|
||||
sf.trie.GetStorage(sf.addr, task.key)
|
||||
}
|
||||
if task.read {
|
||||
sf.seenRead[key] = struct{}{}
|
||||
} else {
|
||||
sf.seenWrite[key] = struct{}{}
|
||||
}
|
||||
sf.seen[string(task)] = struct{}{}
|
||||
}
|
||||
|
||||
case <-sf.stop:
|
||||
|
|
|
|||
|
|
@ -47,15 +47,15 @@ func filledStateDB() *StateDB {
|
|||
|
||||
func TestUseAfterTerminate(t *testing.T) {
|
||||
db := filledStateDB()
|
||||
prefetcher := newTriePrefetcher(db.db, db.originalRoot, "")
|
||||
prefetcher := newTriePrefetcher(db.db, db.originalRoot, "", true)
|
||||
skey := common.HexToHash("aaa")
|
||||
|
||||
if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err != nil {
|
||||
if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}, false); err != nil {
|
||||
t.Errorf("Prefetch failed before terminate: %v", err)
|
||||
}
|
||||
prefetcher.terminate(false)
|
||||
|
||||
if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err == nil {
|
||||
if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}, false); err == nil {
|
||||
t.Errorf("Prefetch succeeded after terminate: %v", err)
|
||||
}
|
||||
if tr := prefetcher.trie(common.Hash{}, db.originalRoot); tr == nil {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package core
|
|||
import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
|
|
@ -31,16 +30,14 @@ import (
|
|||
// data from disk before the main block processor start executing.
|
||||
type statePrefetcher struct {
|
||||
config *params.ChainConfig // Chain configuration options
|
||||
bc *BlockChain // Canonical block chain
|
||||
engine consensus.Engine // Consensus engine used for block rewards
|
||||
chain *HeaderChain // Canonical block chain
|
||||
}
|
||||
|
||||
// newStatePrefetcher initialises a new statePrefetcher.
|
||||
func newStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *statePrefetcher {
|
||||
func newStatePrefetcher(config *params.ChainConfig, chain *HeaderChain) *statePrefetcher {
|
||||
return &statePrefetcher{
|
||||
config: config,
|
||||
bc: bc,
|
||||
engine: engine,
|
||||
chain: chain,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +48,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
|||
var (
|
||||
header = block.Header()
|
||||
gaspool = new(GasPool).AddGas(block.GasLimit())
|
||||
blockContext = NewEVMBlockContext(header, p.bc, nil)
|
||||
blockContext = NewEVMBlockContext(header, p.chain, nil)
|
||||
evm = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
|
||||
signer = types.MakeSigner(p.config, header.Number, header.Time)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
|
@ -37,16 +36,14 @@ import (
|
|||
// StateProcessor implements Processor.
|
||||
type StateProcessor struct {
|
||||
config *params.ChainConfig // Chain configuration options
|
||||
bc *BlockChain // Canonical block chain
|
||||
engine consensus.Engine // Consensus engine used for block rewards
|
||||
chain *HeaderChain // Canonical header chain
|
||||
}
|
||||
|
||||
// NewStateProcessor initialises a new StateProcessor.
|
||||
func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *StateProcessor {
|
||||
func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StateProcessor {
|
||||
return &StateProcessor{
|
||||
config: config,
|
||||
bc: bc,
|
||||
engine: engine,
|
||||
chain: chain,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,10 +70,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
misc.ApplyDAOHardFork(statedb)
|
||||
}
|
||||
var (
|
||||
context = NewEVMBlockContext(header, p.bc, nil)
|
||||
vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg)
|
||||
context vm.BlockContext
|
||||
signer = types.MakeSigner(p.config, header.Number, header.Time)
|
||||
)
|
||||
context = NewEVMBlockContext(header, p.chain, nil)
|
||||
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg)
|
||||
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
||||
ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
||||
}
|
||||
|
|
@ -101,7 +99,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
return nil, nil, 0, errors.New("withdrawals before shanghai")
|
||||
}
|
||||
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
||||
p.engine.Finalize(p.bc, header, statedb, block.Body())
|
||||
p.chain.engine.Finalize(p.chain, header, statedb, block.Body())
|
||||
|
||||
return receipts, allLogs, *usedGas, nil
|
||||
}
|
||||
|
|
|
|||
73
core/stateless.go
Normal file
73
core/stateless.go
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/lru"
|
||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
)
|
||||
|
||||
// ExecuteStateless runs a stateless execution based on a witness, verifies
|
||||
// everything it can locally and returns the two computed fields that need the
|
||||
// other side to explicitly check.
|
||||
//
|
||||
// This method is a bit of a sore thumb here, but:
|
||||
// - It cannot be placed in core/stateless, because state.New prodces a circular dep
|
||||
// - It cannot be placed outside of core, because it needs to construct a dud headerchain
|
||||
//
|
||||
// TODO(karalabe): Would be nice to resolve both issues above somehow and move it.
|
||||
func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (common.Hash, common.Hash, error) {
|
||||
// Create and populate the state database to serve as the stateless backend
|
||||
memdb := witness.MakeHashDB()
|
||||
|
||||
db, err := state.New(witness.Root(), state.NewDatabaseWithConfig(memdb, triedb.HashDefaults), nil)
|
||||
if err != nil {
|
||||
return common.Hash{}, common.Hash{}, err
|
||||
}
|
||||
// Create a blockchain that is idle, but can be used to access headers through
|
||||
chain := &HeaderChain{
|
||||
config: config,
|
||||
chainDb: memdb,
|
||||
headerCache: lru.NewCache[common.Hash, *types.Header](256),
|
||||
engine: beacon.New(ethash.NewFaker()),
|
||||
}
|
||||
processor := NewStateProcessor(config, chain)
|
||||
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
|
||||
|
||||
// Run the stateless blocks processing and self-validate certain fields
|
||||
receipts, _, usedGas, err := processor.Process(witness.Block, db, vm.Config{})
|
||||
if err != nil {
|
||||
return common.Hash{}, common.Hash{}, err
|
||||
}
|
||||
if err = validator.ValidateState(witness.Block, db, receipts, usedGas, true); err != nil {
|
||||
return common.Hash{}, common.Hash{}, err
|
||||
}
|
||||
// Almost everything validated, but receipt and state root needs to be returned
|
||||
receiptRoot := types.DeriveSha(receipts, trie.NewStackTrie(nil))
|
||||
stateRoot := db.IntermediateRoot(config.IsEIP158(witness.Block.Number()))
|
||||
|
||||
return receiptRoot, stateRoot, nil
|
||||
}
|
||||
60
core/stateless/database.go
Normal file
60
core/stateless/database.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package stateless
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
)
|
||||
|
||||
// MakeHashDB imports tries, codes and block hashes from a witness into a new
|
||||
// hash-based memory db. We could eventually rewrite this into a pathdb, but
|
||||
// simple is better for now.
|
||||
func (w *Witness) MakeHashDB() ethdb.Database {
|
||||
var (
|
||||
memdb = rawdb.NewMemoryDatabase()
|
||||
hasher = crypto.NewKeccakState()
|
||||
hash = make([]byte, 32)
|
||||
)
|
||||
// Inject all the "block hashes" (i.e. headers) into the ephemeral database
|
||||
for _, header := range w.Headers {
|
||||
rawdb.WriteHeader(memdb, header)
|
||||
}
|
||||
// Inject all the bytecodes into the ephemeral database
|
||||
for code := range w.Codes {
|
||||
blob := []byte(code)
|
||||
|
||||
hasher.Reset()
|
||||
hasher.Write(blob)
|
||||
hasher.Read(hash)
|
||||
|
||||
rawdb.WriteCode(memdb, common.BytesToHash(hash), blob)
|
||||
}
|
||||
// Inject all the MPT trie nodes into the ephemeral database
|
||||
for node := range w.State {
|
||||
blob := []byte(node)
|
||||
|
||||
hasher.Reset()
|
||||
hasher.Write(blob)
|
||||
hasher.Read(hash)
|
||||
|
||||
rawdb.WriteLegacyTrieNode(memdb, common.BytesToHash(hash), blob)
|
||||
}
|
||||
return memdb
|
||||
}
|
||||
129
core/stateless/encoding.go
Normal file
129
core/stateless/encoding.go
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package stateless
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"slices"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type extWitness -field-override extWitnessMarshalling -out gen_encoding_json.go
|
||||
|
||||
// toExtWitness converts our internal witness representation to the consensus one.
|
||||
func (w *Witness) toExtWitness() *extWitness {
|
||||
ext := &extWitness{
|
||||
Block: w.Block,
|
||||
Headers: w.Headers,
|
||||
}
|
||||
ext.Codes = make([][]byte, 0, len(w.Codes))
|
||||
for code := range w.Codes {
|
||||
ext.Codes = append(ext.Codes, []byte(code))
|
||||
}
|
||||
slices.SortFunc(ext.Codes, bytes.Compare)
|
||||
|
||||
ext.State = make([][]byte, 0, len(w.State))
|
||||
for node := range w.State {
|
||||
ext.State = append(ext.State, []byte(node))
|
||||
}
|
||||
slices.SortFunc(ext.State, bytes.Compare)
|
||||
return ext
|
||||
}
|
||||
|
||||
// fromExtWitness converts the consensus witness format into our internal one.
|
||||
func (w *Witness) fromExtWitness(ext *extWitness) error {
|
||||
w.Block, w.Headers = ext.Block, ext.Headers
|
||||
|
||||
w.Codes = make(map[string]struct{}, len(ext.Codes))
|
||||
for _, code := range ext.Codes {
|
||||
w.Codes[string(code)] = struct{}{}
|
||||
}
|
||||
w.State = make(map[string]struct{}, len(ext.State))
|
||||
for _, node := range ext.State {
|
||||
w.State[string(node)] = struct{}{}
|
||||
}
|
||||
return w.sanitize()
|
||||
}
|
||||
|
||||
// MarshalJSON marshals a witness as JSON.
|
||||
func (w *Witness) MarshalJSON() ([]byte, error) {
|
||||
return w.toExtWitness().MarshalJSON()
|
||||
}
|
||||
|
||||
// EncodeRLP serializes a witness as RLP.
|
||||
func (w *Witness) EncodeRLP(wr io.Writer) error {
|
||||
return rlp.Encode(wr, w.toExtWitness())
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (w *Witness) UnmarshalJSON(input []byte) error {
|
||||
var ext extWitness
|
||||
if err := ext.UnmarshalJSON(input); err != nil {
|
||||
return err
|
||||
}
|
||||
return w.fromExtWitness(&ext)
|
||||
}
|
||||
|
||||
// DecodeRLP decodes a witness from RLP.
|
||||
func (w *Witness) DecodeRLP(s *rlp.Stream) error {
|
||||
var ext extWitness
|
||||
if err := s.Decode(&ext); err != nil {
|
||||
return err
|
||||
}
|
||||
return w.fromExtWitness(&ext)
|
||||
}
|
||||
|
||||
// sanitize checks for some mandatory fields in the witness after decoding so
|
||||
// the rest of the code can assume invariants and doesn't have to deal with
|
||||
// corrupted data.
|
||||
func (w *Witness) sanitize() error {
|
||||
// Verify that the "parent" header (i.e. index 0) is available, and is the
|
||||
// true parent of the block-to-be executed, since we use that to link the
|
||||
// current block to the pre-state.
|
||||
if len(w.Headers) == 0 {
|
||||
return errors.New("parent header (for pre-root hash) missing")
|
||||
}
|
||||
for i, header := range w.Headers {
|
||||
if header == nil {
|
||||
return fmt.Errorf("witness header nil at position %d", i)
|
||||
}
|
||||
}
|
||||
if w.Headers[0].Hash() != w.Block.ParentHash() {
|
||||
return fmt.Errorf("parent hash different: witness %v, block parent %v", w.Headers[0].Hash(), w.Block.ParentHash())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// extWitness is a witness RLP encoding for transferring across clients.
|
||||
type extWitness struct {
|
||||
Block *types.Block `json:"block" gencodec:"required"`
|
||||
Headers []*types.Header `json:"headers" gencodec:"required"`
|
||||
Codes [][]byte `json:"codes"`
|
||||
State [][]byte `json:"state"`
|
||||
}
|
||||
|
||||
// extWitnessMarshalling defines the hex marshalling types for a witness.
|
||||
type extWitnessMarshalling struct {
|
||||
Codes []hexutil.Bytes
|
||||
State []hexutil.Bytes
|
||||
}
|
||||
74
core/stateless/gen_encoding_json.go
Normal file
74
core/stateless/gen_encoding_json.go
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||
|
||||
package stateless
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
var _ = (*extWitnessMarshalling)(nil)
|
||||
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (e extWitness) MarshalJSON() ([]byte, error) {
|
||||
type extWitness struct {
|
||||
Block *types.Block `json:"block" gencodec:"required"`
|
||||
Headers []*types.Header `json:"headers" gencodec:"required"`
|
||||
Codes []hexutil.Bytes `json:"codes"`
|
||||
State []hexutil.Bytes `json:"state"`
|
||||
}
|
||||
var enc extWitness
|
||||
enc.Block = e.Block
|
||||
enc.Headers = e.Headers
|
||||
if e.Codes != nil {
|
||||
enc.Codes = make([]hexutil.Bytes, len(e.Codes))
|
||||
for k, v := range e.Codes {
|
||||
enc.Codes[k] = v
|
||||
}
|
||||
}
|
||||
if e.State != nil {
|
||||
enc.State = make([]hexutil.Bytes, len(e.State))
|
||||
for k, v := range e.State {
|
||||
enc.State[k] = v
|
||||
}
|
||||
}
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (e *extWitness) UnmarshalJSON(input []byte) error {
|
||||
type extWitness struct {
|
||||
Block *types.Block `json:"block" gencodec:"required"`
|
||||
Headers []*types.Header `json:"headers" gencodec:"required"`
|
||||
Codes []hexutil.Bytes `json:"codes"`
|
||||
State []hexutil.Bytes `json:"state"`
|
||||
}
|
||||
var dec extWitness
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
if dec.Block == nil {
|
||||
return errors.New("missing required field 'block' for extWitness")
|
||||
}
|
||||
e.Block = dec.Block
|
||||
if dec.Headers == nil {
|
||||
return errors.New("missing required field 'headers' for extWitness")
|
||||
}
|
||||
e.Headers = dec.Headers
|
||||
if dec.Codes != nil {
|
||||
e.Codes = make([][]byte, len(dec.Codes))
|
||||
for k, v := range dec.Codes {
|
||||
e.Codes[k] = v
|
||||
}
|
||||
}
|
||||
if dec.State != nil {
|
||||
e.State = make([][]byte, len(dec.State))
|
||||
for k, v := range dec.State {
|
||||
e.State[k] = v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
159
core/stateless/witness.go
Normal file
159
core/stateless/witness.go
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package stateless
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// HeaderReader is an interface to pull in headers in place of block hashes for
|
||||
// the witness.
|
||||
type HeaderReader interface {
|
||||
// GetHeader retrieves a block header from the database by hash and number,
|
||||
GetHeader(hash common.Hash, number uint64) *types.Header
|
||||
}
|
||||
|
||||
// Witness encompasses a block, state and any other chain data required to apply
|
||||
// a set of transactions and derive a post state/receipt root.
|
||||
type Witness struct {
|
||||
Block *types.Block // Current block with rootHash and receiptHash zeroed out
|
||||
Headers []*types.Header // Past headers in reverse order (0=parent, 1=parent's-parent, etc). First *must* be set.
|
||||
Codes map[string]struct{} // Set of bytecodes ran or accessed
|
||||
State map[string]struct{} // Set of MPT state trie nodes (account and storage together)
|
||||
|
||||
chain HeaderReader // Chain reader to convert block hash ops to header proofs
|
||||
lock sync.Mutex // Lock to allow concurrent state insertions
|
||||
}
|
||||
|
||||
// NewWitness creates an empty witness ready for population.
|
||||
func NewWitness(chain HeaderReader, block *types.Block) (*Witness, error) {
|
||||
// Zero out the result fields to avoid accidentally sending them to the verifier
|
||||
header := block.Header()
|
||||
header.Root = common.Hash{}
|
||||
header.ReceiptHash = common.Hash{}
|
||||
|
||||
// Retrieve the parent header, which will *always* be included to act as a
|
||||
// trustless pre-root hash container
|
||||
parent := chain.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
||||
if parent == nil {
|
||||
return nil, errors.New("failed to retrieve parent header")
|
||||
}
|
||||
// Create the wtness with a reconstructed gutted out block
|
||||
return &Witness{
|
||||
Block: types.NewBlockWithHeader(header).WithBody(*block.Body()),
|
||||
Codes: make(map[string]struct{}),
|
||||
State: make(map[string]struct{}),
|
||||
Headers: []*types.Header{parent},
|
||||
chain: chain,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AddBlockHash adds a "blockhash" to the witness with the designated offset from
|
||||
// chain head. Under the hood, this method actually pulls in enough headers from
|
||||
// the chain to cover the block being added.
|
||||
func (w *Witness) AddBlockHash(number uint64) {
|
||||
// Keep pulling in headers until this hash is populated
|
||||
for int(w.Block.NumberU64()-number) > len(w.Headers) {
|
||||
tail := w.Block.Header()
|
||||
if len(w.Headers) > 0 {
|
||||
tail = w.Headers[len(w.Headers)-1]
|
||||
}
|
||||
w.Headers = append(w.Headers, w.chain.GetHeader(tail.ParentHash, tail.Number.Uint64()-1))
|
||||
}
|
||||
}
|
||||
|
||||
// AddCode adds a bytecode blob to the witness.
|
||||
func (w *Witness) AddCode(code []byte) {
|
||||
if len(code) == 0 {
|
||||
return
|
||||
}
|
||||
w.Codes[string(code)] = struct{}{}
|
||||
}
|
||||
|
||||
// AddState inserts a batch of MPT trie nodes into the witness.
|
||||
func (w *Witness) AddState(nodes map[string]struct{}) {
|
||||
if len(nodes) == 0 {
|
||||
return
|
||||
}
|
||||
w.lock.Lock()
|
||||
defer w.lock.Unlock()
|
||||
|
||||
for node := range nodes {
|
||||
w.State[node] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy deep-copies the witness object. Witness.Block isn't deep-copied as it
|
||||
// is never mutated by Witness
|
||||
func (w *Witness) Copy() *Witness {
|
||||
return &Witness{
|
||||
Block: w.Block,
|
||||
Headers: slices.Clone(w.Headers),
|
||||
Codes: maps.Clone(w.Codes),
|
||||
State: maps.Clone(w.State),
|
||||
}
|
||||
}
|
||||
|
||||
// String prints a human-readable summary containing the total size of the
|
||||
// witness and the sizes of the underlying components
|
||||
func (w *Witness) String() string {
|
||||
blob, _ := rlp.EncodeToBytes(w)
|
||||
bytesTotal := len(blob)
|
||||
|
||||
blob, _ = rlp.EncodeToBytes(w.Block)
|
||||
bytesBlock := len(blob)
|
||||
|
||||
bytesHeaders := 0
|
||||
for _, header := range w.Headers {
|
||||
blob, _ = rlp.EncodeToBytes(header)
|
||||
bytesHeaders += len(blob)
|
||||
}
|
||||
bytesCodes := 0
|
||||
for code := range w.Codes {
|
||||
bytesCodes += len(code)
|
||||
}
|
||||
bytesState := 0
|
||||
for node := range w.State {
|
||||
bytesState += len(node)
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
fmt.Fprintf(buf, "Witness #%d: %v\n", w.Block.Number(), common.StorageSize(bytesTotal))
|
||||
fmt.Fprintf(buf, " block (%4d txs): %10v\n", len(w.Block.Transactions()), common.StorageSize(bytesBlock))
|
||||
fmt.Fprintf(buf, "%4d headers: %10v\n", len(w.Headers), common.StorageSize(bytesHeaders))
|
||||
fmt.Fprintf(buf, "%4d trie nodes: %10v\n", len(w.State), common.StorageSize(bytesState))
|
||||
fmt.Fprintf(buf, "%4d codes: %10v\n", len(w.Codes), common.StorageSize(bytesCodes))
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Root returns the pre-state root from the first header.
|
||||
//
|
||||
// Note, this method will panic in case of a bad witness (but RLP decoding will
|
||||
// sanitize it and fail before that).
|
||||
func (w *Witness) Root() common.Hash {
|
||||
return w.Headers[0].Root
|
||||
}
|
||||
|
|
@ -199,7 +199,7 @@ type Hooks struct {
|
|||
// for tracing and reporting.
|
||||
type BalanceChangeReason byte
|
||||
|
||||
//go:generate stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go
|
||||
//go:generate go run golang.org/x/tools/cmd/stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go
|
||||
|
||||
const (
|
||||
BalanceChangeUnspecified BalanceChangeReason = 0
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres
|
|||
if p.head.ExcessBlobGas != nil {
|
||||
blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(*p.head.ExcessBlobGas))
|
||||
}
|
||||
p.evict = newPriceHeap(basefee, blobfee, &p.index)
|
||||
p.evict = newPriceHeap(basefee, blobfee, p.index)
|
||||
|
||||
// Pool initialized, attach the blob limbo to it to track blobs included
|
||||
// recently but not yet finalized
|
||||
|
|
@ -1116,7 +1116,7 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error {
|
|||
ExistingCost: func(addr common.Address, nonce uint64) *big.Int {
|
||||
next := p.state.GetNonce(addr)
|
||||
if uint64(len(p.index[addr])) > nonce-next {
|
||||
return p.index[addr][int(tx.Nonce()-next)].costCap.ToBig()
|
||||
return p.index[addr][int(nonce-next)].costCap.ToBig()
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
|
@ -1598,6 +1598,7 @@ func (p *BlobPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs bool
|
|||
// Nonce returns the next nonce of an account, with all transactions executable
|
||||
// by the pool already applied on top.
|
||||
func (p *BlobPool) Nonce(addr common.Address) uint64 {
|
||||
// We need a write lock here, since state.GetNonce might write the cache.
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
|
|
@ -1610,8 +1611,8 @@ func (p *BlobPool) Nonce(addr common.Address) uint64 {
|
|||
// Stats retrieves the current pool stats, namely the number of pending and the
|
||||
// number of queued (non-executable) transactions.
|
||||
func (p *BlobPool) Stats() (int, int) {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
p.lock.RLock()
|
||||
defer p.lock.RUnlock()
|
||||
|
||||
var pending int
|
||||
for _, txs := range p.index {
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ func (bc *testBlockChain) CurrentFinalBlock() *types.Header {
|
|||
}
|
||||
}
|
||||
|
||||
func (bt *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
|
||||
func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@
|
|||
package blobpool
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"container/heap"
|
||||
"math"
|
||||
"sort"
|
||||
"slices"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/holiman/uint256"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
// evictHeap is a helper data structure to keep track of the cheapest bottleneck
|
||||
|
|
@ -35,7 +35,7 @@ import (
|
|||
// The goal of the heap is to decide which account has the worst bottleneck to
|
||||
// evict transactions from.
|
||||
type evictHeap struct {
|
||||
metas *map[common.Address][]*blobTxMeta // Pointer to the blob pool's index for price retrievals
|
||||
metas map[common.Address][]*blobTxMeta // Pointer to the blob pool's index for price retrievals
|
||||
|
||||
basefeeJumps float64 // Pre-calculated absolute dynamic fee jumps for the base fee
|
||||
blobfeeJumps float64 // Pre-calculated absolute dynamic fee jumps for the blob fee
|
||||
|
|
@ -46,23 +46,18 @@ type evictHeap struct {
|
|||
|
||||
// newPriceHeap creates a new heap of cheapest accounts in the blob pool to evict
|
||||
// from in case of over saturation.
|
||||
func newPriceHeap(basefee *uint256.Int, blobfee *uint256.Int, index *map[common.Address][]*blobTxMeta) *evictHeap {
|
||||
func newPriceHeap(basefee *uint256.Int, blobfee *uint256.Int, index map[common.Address][]*blobTxMeta) *evictHeap {
|
||||
heap := &evictHeap{
|
||||
metas: index,
|
||||
index: make(map[common.Address]int),
|
||||
index: make(map[common.Address]int, len(index)),
|
||||
}
|
||||
// Populate the heap in account sort order. Not really needed in practice,
|
||||
// but it makes the heap initialization deterministic and less annoying to
|
||||
// test in unit tests.
|
||||
addrs := make([]common.Address, 0, len(*index))
|
||||
for addr := range *index {
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
sort.Slice(addrs, func(i, j int) bool { return bytes.Compare(addrs[i][:], addrs[j][:]) < 0 })
|
||||
|
||||
for _, addr := range addrs {
|
||||
heap.index[addr] = len(heap.addrs)
|
||||
heap.addrs = append(heap.addrs, addr)
|
||||
heap.addrs = maps.Keys(index)
|
||||
slices.SortFunc(heap.addrs, common.Address.Cmp)
|
||||
for i, addr := range heap.addrs {
|
||||
heap.index[addr] = i
|
||||
}
|
||||
heap.reinit(basefee, blobfee, true)
|
||||
return heap
|
||||
|
|
@ -94,8 +89,8 @@ func (h *evictHeap) Len() int {
|
|||
// Less implements sort.Interface as part of heap.Interface, returning which of
|
||||
// the two requested accounts has a cheaper bottleneck.
|
||||
func (h *evictHeap) Less(i, j int) bool {
|
||||
txsI := (*(h.metas))[h.addrs[i]]
|
||||
txsJ := (*(h.metas))[h.addrs[j]]
|
||||
txsI := h.metas[h.addrs[i]]
|
||||
txsJ := h.metas[h.addrs[j]]
|
||||
|
||||
lastI := txsI[len(txsI)-1]
|
||||
lastJ := txsJ[len(txsJ)-1]
|
||||
|
|
|
|||
|
|
@ -37,17 +37,17 @@ func verifyHeapInternals(t *testing.T, evict *evictHeap) {
|
|||
seen := make(map[common.Address]struct{})
|
||||
for i, addr := range evict.addrs {
|
||||
seen[addr] = struct{}{}
|
||||
if _, ok := (*evict.metas)[addr]; !ok {
|
||||
if _, ok := evict.metas[addr]; !ok {
|
||||
t.Errorf("heap contains unexpected address at slot %d: %v", i, addr)
|
||||
}
|
||||
}
|
||||
for addr := range *evict.metas {
|
||||
for addr := range evict.metas {
|
||||
if _, ok := seen[addr]; !ok {
|
||||
t.Errorf("heap is missing required address %v", addr)
|
||||
}
|
||||
}
|
||||
if len(evict.addrs) != len(*evict.metas) {
|
||||
t.Errorf("heap size %d mismatches metadata size %d", len(evict.addrs), len(*evict.metas))
|
||||
if len(evict.addrs) != len(evict.metas) {
|
||||
t.Errorf("heap size %d mismatches metadata size %d", len(evict.addrs), len(evict.metas))
|
||||
}
|
||||
// Ensure that all accounts are present in the heap order index and no extras
|
||||
have := make([]common.Address, len(evict.index))
|
||||
|
|
@ -159,7 +159,7 @@ func TestPriceHeapSorting(t *testing.T) {
|
|||
}}
|
||||
}
|
||||
// Create a price heap and check the pop order
|
||||
priceheap := newPriceHeap(uint256.NewInt(tt.basefee), uint256.NewInt(tt.blobfee), &index)
|
||||
priceheap := newPriceHeap(uint256.NewInt(tt.basefee), uint256.NewInt(tt.blobfee), index)
|
||||
verifyHeapInternals(t, priceheap)
|
||||
|
||||
for j := 0; j < len(tt.order); j++ {
|
||||
|
|
@ -218,7 +218,7 @@ func benchmarkPriceHeapReinit(b *testing.B, datacap uint64) {
|
|||
}}
|
||||
}
|
||||
// Create a price heap and reinit it over and over
|
||||
heap := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), &index)
|
||||
heap := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), index)
|
||||
|
||||
basefees := make([]*uint256.Int, b.N)
|
||||
blobfees := make([]*uint256.Int, b.N)
|
||||
|
|
@ -278,7 +278,7 @@ func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) {
|
|||
}}
|
||||
}
|
||||
// Create a price heap and overflow it over and over
|
||||
evict := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), &index)
|
||||
evict := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), index)
|
||||
var (
|
||||
addrs = make([]common.Address, b.N)
|
||||
metas = make([]*blobTxMeta, b.N)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ package core
|
|||
import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
)
|
||||
|
|
@ -33,7 +35,10 @@ type Validator interface {
|
|||
|
||||
// ValidateState validates the given statedb and optionally the receipts and
|
||||
// gas used.
|
||||
ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error
|
||||
ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error
|
||||
|
||||
// ValidateWitness cross validates a block execution with stateless remote clients.
|
||||
ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error
|
||||
}
|
||||
|
||||
// Prefetcher is an interface for pre-caching transaction signatures and state.
|
||||
|
|
|
|||
|
|
@ -459,11 +459,11 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
|
|||
// homestead rules.
|
||||
type HomesteadSigner struct{ FrontierSigner }
|
||||
|
||||
func (s HomesteadSigner) ChainID() *big.Int {
|
||||
func (hs HomesteadSigner) ChainID() *big.Int {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s HomesteadSigner) Equal(s2 Signer) bool {
|
||||
func (hs HomesteadSigner) Equal(s2 Signer) bool {
|
||||
_, ok := s2.(HomesteadSigner)
|
||||
return ok
|
||||
}
|
||||
|
|
@ -486,11 +486,11 @@ func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
|
|||
// frontier rules.
|
||||
type FrontierSigner struct{}
|
||||
|
||||
func (s FrontierSigner) ChainID() *big.Int {
|
||||
func (fs FrontierSigner) ChainID() *big.Int {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s FrontierSigner) Equal(s2 Signer) bool {
|
||||
func (fs FrontierSigner) Equal(s2 Signer) bool {
|
||||
_, ok := s2.(FrontierSigner)
|
||||
return ok
|
||||
}
|
||||
|
|
@ -572,6 +572,6 @@ func deriveChainId(v *big.Int) *big.Int {
|
|||
}
|
||||
return new(big.Int).SetUint64((v - 35) / 2)
|
||||
}
|
||||
v = new(big.Int).Sub(v, big.NewInt(35))
|
||||
return v.Div(v, big.NewInt(2))
|
||||
vCopy := new(big.Int).Sub(v, big.NewInt(35))
|
||||
return vCopy.Rsh(vCopy, 1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -345,6 +345,41 @@ func TestTransactionCoding(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestLegacyTransaction_ConsistentV_LargeChainIds(t *testing.T) {
|
||||
chainId := new(big.Int).SetUint64(13317435930671861669)
|
||||
|
||||
txdata := &LegacyTx{
|
||||
Nonce: 1,
|
||||
Gas: 1,
|
||||
GasPrice: big.NewInt(2),
|
||||
Data: []byte("abcdef"),
|
||||
}
|
||||
|
||||
key, err := crypto.GenerateKey()
|
||||
if err != nil {
|
||||
t.Fatalf("could not generate key: %v", err)
|
||||
}
|
||||
|
||||
tx, err := SignNewTx(key, NewEIP2930Signer(chainId), txdata)
|
||||
if err != nil {
|
||||
t.Fatalf("could not sign transaction: %v", err)
|
||||
}
|
||||
|
||||
// Make a copy of the initial V value
|
||||
preV, _, _ := tx.RawSignatureValues()
|
||||
preV = new(big.Int).Set(preV)
|
||||
|
||||
if tx.ChainId().Cmp(chainId) != 0 {
|
||||
t.Fatalf("wrong chain id: %v", tx.ChainId())
|
||||
}
|
||||
|
||||
v, _, _ := tx.RawSignatureValues()
|
||||
|
||||
if v.Cmp(preV) != 0 {
|
||||
t.Fatalf("wrong v value: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeDecodeJSON(tx *Transaction) (*Transaction, error) {
|
||||
data, err := json.Marshal(tx)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -332,10 +332,7 @@ type bigModExp struct {
|
|||
var (
|
||||
big1 = big.NewInt(1)
|
||||
big3 = big.NewInt(3)
|
||||
big4 = big.NewInt(4)
|
||||
big7 = big.NewInt(7)
|
||||
big8 = big.NewInt(8)
|
||||
big16 = big.NewInt(16)
|
||||
big20 = big.NewInt(20)
|
||||
big32 = big.NewInt(32)
|
||||
big64 = big.NewInt(64)
|
||||
|
|
@ -361,13 +358,13 @@ func modexpMultComplexity(x *big.Int) *big.Int {
|
|||
case x.Cmp(big1024) <= 0:
|
||||
// (x ** 2 // 4 ) + ( 96 * x - 3072)
|
||||
x = new(big.Int).Add(
|
||||
new(big.Int).Div(new(big.Int).Mul(x, x), big4),
|
||||
new(big.Int).Rsh(new(big.Int).Mul(x, x), 2),
|
||||
new(big.Int).Sub(new(big.Int).Mul(big96, x), big3072),
|
||||
)
|
||||
default:
|
||||
// (x ** 2 // 16) + (480 * x - 199680)
|
||||
x = new(big.Int).Add(
|
||||
new(big.Int).Div(new(big.Int).Mul(x, x), big16),
|
||||
new(big.Int).Rsh(new(big.Int).Mul(x, x), 4),
|
||||
new(big.Int).Sub(new(big.Int).Mul(big480, x), big199680),
|
||||
)
|
||||
}
|
||||
|
|
@ -405,7 +402,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
|
|||
adjExpLen := new(big.Int)
|
||||
if expLen.Cmp(big32) > 0 {
|
||||
adjExpLen.Sub(expLen, big32)
|
||||
adjExpLen.Mul(big8, adjExpLen)
|
||||
adjExpLen.Lsh(adjExpLen, 3)
|
||||
}
|
||||
adjExpLen.Add(adjExpLen, big.NewInt(int64(msb)))
|
||||
// Calculate the gas cost of the operation
|
||||
|
|
@ -419,8 +416,8 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 {
|
|||
// ceiling(x/8)^2
|
||||
//
|
||||
//where is x is max(length_of_MODULUS, length_of_BASE)
|
||||
gas = gas.Add(gas, big7)
|
||||
gas = gas.Div(gas, big8)
|
||||
gas.Add(gas, big7)
|
||||
gas.Rsh(gas, 3)
|
||||
gas.Mul(gas, gas)
|
||||
|
||||
gas.Mul(gas, math.BigMax(adjExpLen, big1))
|
||||
|
|
|
|||
|
|
@ -213,6 +213,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||
// The contract is a scoped environment for this execution context only.
|
||||
code := evm.StateDB.GetCode(addr)
|
||||
if witness := evm.StateDB.Witness(); witness != nil {
|
||||
witness.AddCode(code)
|
||||
}
|
||||
if len(code) == 0 {
|
||||
ret, err = nil, nil // gas is unchanged
|
||||
} else {
|
||||
|
|
@ -280,6 +283,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
|||
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||
// The contract is a scoped environment for this execution context only.
|
||||
contract := NewContract(caller, AccountRef(caller.Address()), value, gas)
|
||||
if witness := evm.StateDB.Witness(); witness != nil {
|
||||
witness.AddCode(evm.StateDB.GetCode(addrCopy))
|
||||
}
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
||||
ret, err = evm.interpreter.Run(contract, input, false)
|
||||
gas = contract.Gas
|
||||
|
|
@ -327,6 +333,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
|||
addrCopy := addr
|
||||
// Initialise a new contract and make initialise the delegate values
|
||||
contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate()
|
||||
if witness := evm.StateDB.Witness(); witness != nil {
|
||||
witness.AddCode(evm.StateDB.GetCode(addrCopy))
|
||||
}
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
||||
ret, err = evm.interpreter.Run(contract, input, false)
|
||||
gas = contract.Gas
|
||||
|
|
@ -382,6 +391,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
|||
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||
// The contract is a scoped environment for this execution context only.
|
||||
contract := NewContract(caller, AccountRef(addrCopy), new(uint256.Int), gas)
|
||||
if witness := evm.StateDB.Witness(); witness != nil {
|
||||
witness.AddCode(evm.StateDB.GetCode(addrCopy))
|
||||
}
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
||||
// When an error was returned by the EVM or when setting the creation code
|
||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||
|
|
|
|||
|
|
@ -340,6 +340,10 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
|
|||
|
||||
func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||
slot := scope.Stack.peek()
|
||||
address := slot.Bytes20()
|
||||
if witness := interpreter.evm.StateDB.Witness(); witness != nil {
|
||||
witness.AddCode(interpreter.evm.StateDB.GetCode(address))
|
||||
}
|
||||
slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20())))
|
||||
return nil, nil
|
||||
}
|
||||
|
|
@ -378,7 +382,11 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
|||
uint64CodeOffset = math.MaxUint64
|
||||
}
|
||||
addr := common.Address(a.Bytes20())
|
||||
codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
|
||||
code := interpreter.evm.StateDB.GetCode(addr)
|
||||
if witness := interpreter.evm.StateDB.Witness(); witness != nil {
|
||||
witness.AddCode(code)
|
||||
}
|
||||
codeCopy := getData(code, uint64CodeOffset, length.Uint64())
|
||||
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||
|
||||
return nil, nil
|
||||
|
|
@ -443,7 +451,11 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
|||
lower = upper - 256
|
||||
}
|
||||
if num64 >= lower && num64 < upper {
|
||||
num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes())
|
||||
res := interpreter.evm.Context.GetHash(num64)
|
||||
if witness := interpreter.evm.StateDB.Witness(); witness != nil {
|
||||
witness.AddBlockHash(num64)
|
||||
}
|
||||
num.SetBytes(res[:])
|
||||
} else {
|
||||
num.Clear()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
|
@ -87,6 +88,8 @@ type StateDB interface {
|
|||
|
||||
AddLog(*types.Log)
|
||||
AddPreimage(common.Hash, []byte)
|
||||
|
||||
Witness() *stateless.Witness
|
||||
}
|
||||
|
||||
// CallContext provides a basic interface for the EVM calling conventions. The EVM
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ type Config struct {
|
|||
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
|
||||
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
|
||||
ExtraEips []int // Additional EIPS that are to be enabled
|
||||
EnableWitnessCollection bool // true if witness collection is enabled
|
||||
}
|
||||
|
||||
// ScopeContext contains the things that are per-call, such as stack and memory,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ const RecoveryIDOffset = 64
|
|||
const DigestLength = 32
|
||||
|
||||
var (
|
||||
secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
|
||||
secp256k1N = S256().Params().N
|
||||
secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2))
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
var (
|
||||
vmConfig = vm.Config{
|
||||
EnablePreimageRecording: config.EnablePreimageRecording,
|
||||
EnableWitnessCollection: config.EnableWitnessCollection,
|
||||
}
|
||||
cacheConfig = &core.CacheConfig{
|
||||
TrieCleanLimit: config.TrieCleanCache,
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
|
|||
log.Warn("Final block not available in database", "hash", update.FinalizedBlockHash)
|
||||
return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("final block not available in database"))
|
||||
} else if rawdb.ReadCanonicalHash(api.eth.ChainDb(), finalBlock.NumberU64()) != update.FinalizedBlockHash {
|
||||
log.Warn("Final block not in canonical chain", "number", block.NumberU64(), "hash", update.HeadBlockHash)
|
||||
log.Warn("Final block not in canonical chain", "number", finalBlock.NumberU64(), "hash", update.FinalizedBlockHash)
|
||||
return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("final block not in canonical chain"))
|
||||
}
|
||||
// Set the finalized block
|
||||
|
|
|
|||
|
|
@ -141,6 +141,9 @@ type Config struct {
|
|||
// Enables tracking of SHA3 preimages in the VM
|
||||
EnablePreimageRecording bool
|
||||
|
||||
// Enables prefetching trie nodes for read operations too
|
||||
EnableWitnessCollection bool `toml:"-"`
|
||||
|
||||
// Enables VM tracing
|
||||
VMTrace string
|
||||
VMTraceJsonConfig string
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||
BlobPool blobpool.Config
|
||||
GPO gasprice.Config
|
||||
EnablePreimageRecording bool
|
||||
EnableWitnessCollection bool `toml:"-"`
|
||||
VMTrace string
|
||||
VMTraceJsonConfig string
|
||||
DocRoot string `toml:"-"`
|
||||
|
|
@ -93,6 +94,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||
enc.BlobPool = c.BlobPool
|
||||
enc.GPO = c.GPO
|
||||
enc.EnablePreimageRecording = c.EnablePreimageRecording
|
||||
enc.EnableWitnessCollection = c.EnableWitnessCollection
|
||||
enc.VMTrace = c.VMTrace
|
||||
enc.VMTraceJsonConfig = c.VMTraceJsonConfig
|
||||
enc.DocRoot = c.DocRoot
|
||||
|
|
@ -140,6 +142,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||
BlobPool *blobpool.Config
|
||||
GPO *gasprice.Config
|
||||
EnablePreimageRecording *bool
|
||||
EnableWitnessCollection *bool `toml:"-"`
|
||||
VMTrace *string
|
||||
VMTraceJsonConfig *string
|
||||
DocRoot *string `toml:"-"`
|
||||
|
|
@ -252,6 +255,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||
if dec.EnablePreimageRecording != nil {
|
||||
c.EnablePreimageRecording = *dec.EnablePreimageRecording
|
||||
}
|
||||
if dec.EnableWitnessCollection != nil {
|
||||
c.EnableWitnessCollection = *dec.EnableWitnessCollection
|
||||
}
|
||||
if dec.VMTrace != nil {
|
||||
c.VMTrace = *dec.VMTrace
|
||||
}
|
||||
|
|
|
|||
|
|
@ -332,11 +332,7 @@ func ServiceGetAccountRangeQuery(chain *core.BlockChain, req *GetAccountRangePac
|
|||
return nil, nil
|
||||
}
|
||||
}
|
||||
var proofs [][]byte
|
||||
for _, blob := range proof.List() {
|
||||
proofs = append(proofs, blob)
|
||||
}
|
||||
return accounts, proofs
|
||||
return accounts, proof.List()
|
||||
}
|
||||
|
||||
func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesPacket) ([][]*StorageData, [][]byte) {
|
||||
|
|
@ -438,9 +434,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP
|
|||
return nil, nil
|
||||
}
|
||||
}
|
||||
for _, blob := range proof.List() {
|
||||
proofs = append(proofs, blob)
|
||||
}
|
||||
proofs = append(proofs, proof.List()...)
|
||||
// Proof terminates the reply as proofs are only added if a node
|
||||
// refuses to serve more data (exception when a contract fetch is
|
||||
// finishing, but that's that).
|
||||
|
|
|
|||
|
|
@ -286,10 +286,7 @@ func createAccountRequestResponse(t *testPeer, root common.Hash, origin common.H
|
|||
t.logger.Error("Could not prove last item", "error", err)
|
||||
}
|
||||
}
|
||||
for _, blob := range proof.List() {
|
||||
proofs = append(proofs, blob)
|
||||
}
|
||||
return keys, vals, proofs
|
||||
return keys, vals, proof.List()
|
||||
}
|
||||
|
||||
// defaultStorageRequestHandler is a well-behaving storage request handler
|
||||
|
|
@ -371,9 +368,7 @@ func createStorageRequestResponse(t *testPeer, root common.Hash, accounts []comm
|
|||
t.logger.Error("Could not prove last item", "error", err)
|
||||
}
|
||||
}
|
||||
for _, blob := range proof.List() {
|
||||
proofs = append(proofs, blob)
|
||||
}
|
||||
proofs = append(proofs, proof.List()...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -430,9 +425,7 @@ func createStorageRequestResponseAlwaysProve(t *testPeer, root common.Hash, acco
|
|||
t.logger.Error("Could not prove last item", "error", err)
|
||||
}
|
||||
}
|
||||
for _, blob := range proof.List() {
|
||||
proofs = append(proofs, blob)
|
||||
}
|
||||
proofs = append(proofs, proof.List()...)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -586,9 +579,8 @@ func testSyncBloatedProof(t *testing.T, scheme string) {
|
|||
|
||||
source.accountRequestHandler = func(t *testPeer, requestId uint64, root common.Hash, origin common.Hash, limit common.Hash, cap uint64) error {
|
||||
var (
|
||||
proofs [][]byte
|
||||
keys []common.Hash
|
||||
vals [][]byte
|
||||
keys []common.Hash
|
||||
vals [][]byte
|
||||
)
|
||||
// The values
|
||||
for _, entry := range t.accountValues {
|
||||
|
|
@ -618,10 +610,7 @@ func testSyncBloatedProof(t *testing.T, scheme string) {
|
|||
keys = append(keys[:1], keys[2:]...)
|
||||
vals = append(vals[:1], vals[2:]...)
|
||||
}
|
||||
for _, blob := range proof.List() {
|
||||
proofs = append(proofs, blob)
|
||||
}
|
||||
if err := t.remote.OnAccounts(t, requestId, keys, vals, proofs); err != nil {
|
||||
if err := t.remote.OnAccounts(t, requestId, keys, vals, proof.List()); err != nil {
|
||||
t.logger.Info("remote error on delivery (as expected)", "error", err)
|
||||
t.term()
|
||||
// This is actually correct, signal to exit the test successfully
|
||||
|
|
@ -1525,7 +1514,7 @@ func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv)
|
|||
|
||||
// Commit the state changes into db and re-create the trie
|
||||
// for accessing later.
|
||||
root, nodes, _ := accTrie.Commit(false)
|
||||
root, nodes := accTrie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
accTrie, _ = trie.New(trie.StateTrieID(root), db)
|
||||
|
|
@ -1587,7 +1576,7 @@ func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) {
|
|||
|
||||
// Commit the state changes into db and re-create the trie
|
||||
// for accessing later.
|
||||
root, nodes, _ := accTrie.Commit(false)
|
||||
root, nodes := accTrie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
accTrie, _ = trie.New(trie.StateTrieID(root), db)
|
||||
|
|
@ -1633,7 +1622,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots
|
|||
slices.SortFunc(entries, (*kv).cmp)
|
||||
|
||||
// Commit account trie
|
||||
root, set, _ := accTrie.Commit(true)
|
||||
root, set := accTrie.Commit(true)
|
||||
nodes.Merge(set)
|
||||
|
||||
// Commit gathered dirty nodes into database
|
||||
|
|
@ -1700,7 +1689,7 @@ func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, bounda
|
|||
slices.SortFunc(entries, (*kv).cmp)
|
||||
|
||||
// Commit account trie
|
||||
root, set, _ := accTrie.Commit(true)
|
||||
root, set := accTrie.Commit(true)
|
||||
nodes.Merge(set)
|
||||
|
||||
// Commit gathered dirty nodes into database
|
||||
|
|
@ -1742,7 +1731,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *triedb.Datab
|
|||
entries = append(entries, elem)
|
||||
}
|
||||
slices.SortFunc(entries, (*kv).cmp)
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes := trie.Commit(false)
|
||||
return root, nodes, entries
|
||||
}
|
||||
|
||||
|
|
@ -1793,7 +1782,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *triedb.Database) (com
|
|||
entries = append(entries, elem)
|
||||
}
|
||||
slices.SortFunc(entries, (*kv).cmp)
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes := trie.Commit(false)
|
||||
return root, nodes, entries
|
||||
}
|
||||
|
||||
|
|
@ -1825,7 +1814,7 @@ func makeUnevenStorageTrie(owner common.Hash, slots int, db *triedb.Database) (c
|
|||
}
|
||||
}
|
||||
slices.SortFunc(entries, (*kv).cmp)
|
||||
root, nodes, _ := tr.Commit(false)
|
||||
root, nodes := tr.Commit(false)
|
||||
return root, nodes, entries
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -204,12 +204,10 @@ func (s *supply) internalTxsHandler(call *supplyTxCallstack) {
|
|||
s.delta.Burn.Misc.Add(s.delta.Burn.Misc, call.burn)
|
||||
}
|
||||
|
||||
if len(call.calls) > 0 {
|
||||
// Recursively handle internal calls
|
||||
for _, call := range call.calls {
|
||||
callCopy := call
|
||||
s.internalTxsHandler(&callCopy)
|
||||
}
|
||||
// Recursively handle internal calls
|
||||
for _, call := range call.calls {
|
||||
callCopy := call
|
||||
s.internalTxsHandler(&callCopy)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -274,16 +274,14 @@ func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx
|
|||
}
|
||||
|
||||
output = append(output, *frame)
|
||||
if len(input.Calls) > 0 {
|
||||
for i, childCall := range input.Calls {
|
||||
childAddr := childTraceAddress(traceAddress, i)
|
||||
childCallCopy := childCall
|
||||
flat, err := flatFromNested(&childCallCopy, childAddr, convertErrs, ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
output = append(output, flat...)
|
||||
for i, childCall := range input.Calls {
|
||||
childAddr := childTraceAddress(traceAddress, i)
|
||||
childCallCopy := childCall
|
||||
flat, err := flatFromNested(&childCallCopy, childAddr, convertErrs, ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
output = append(output, flat...)
|
||||
}
|
||||
|
||||
return output, nil
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ type KeyValueWriter interface {
|
|||
|
||||
// KeyValueStater wraps the Stat method of a backing data store.
|
||||
type KeyValueStater interface {
|
||||
// Stat returns a particular internal stat of the database.
|
||||
Stat(property string) (string, error)
|
||||
// Stat returns the statistic data of the database.
|
||||
Stat() (string, error)
|
||||
}
|
||||
|
||||
// Compacter wraps the Compact method of a backing data store.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ package leveldb
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -244,14 +243,53 @@ func (db *Database) NewSnapshot() (ethdb.Snapshot, error) {
|
|||
return &snapshot{db: snap}, nil
|
||||
}
|
||||
|
||||
// Stat returns a particular internal stat of the database.
|
||||
func (db *Database) Stat(property string) (string, error) {
|
||||
if property == "" {
|
||||
property = "leveldb.stats"
|
||||
} else if !strings.HasPrefix(property, "leveldb.") {
|
||||
property = "leveldb." + property
|
||||
// Stat returns the statistic data of the database.
|
||||
func (db *Database) Stat() (string, error) {
|
||||
var stats leveldb.DBStats
|
||||
if err := db.db.Stats(&stats); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return db.db.GetProperty(property)
|
||||
var (
|
||||
message string
|
||||
totalRead int64
|
||||
totalWrite int64
|
||||
totalSize int64
|
||||
totalTables int
|
||||
totalDuration time.Duration
|
||||
)
|
||||
if len(stats.LevelSizes) > 0 {
|
||||
message += " Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)\n" +
|
||||
"-------+------------+---------------+---------------+---------------+---------------\n"
|
||||
for level, size := range stats.LevelSizes {
|
||||
read := stats.LevelRead[level]
|
||||
write := stats.LevelWrite[level]
|
||||
duration := stats.LevelDurations[level]
|
||||
tables := stats.LevelTablesCounts[level]
|
||||
|
||||
if tables == 0 && duration == 0 {
|
||||
continue
|
||||
}
|
||||
totalTables += tables
|
||||
totalSize += size
|
||||
totalRead += read
|
||||
totalWrite += write
|
||||
totalDuration += duration
|
||||
message += fmt.Sprintf(" %3d | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n",
|
||||
level, tables, float64(size)/1048576.0, duration.Seconds(),
|
||||
float64(read)/1048576.0, float64(write)/1048576.0)
|
||||
}
|
||||
message += "-------+------------+---------------+---------------+---------------+---------------\n"
|
||||
message += fmt.Sprintf(" Total | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n",
|
||||
totalTables, float64(totalSize)/1048576.0, totalDuration.Seconds(),
|
||||
float64(totalRead)/1048576.0, float64(totalWrite)/1048576.0)
|
||||
message += "-------+------------+---------------+---------------+---------------+---------------\n\n"
|
||||
}
|
||||
message += fmt.Sprintf("Read(MB):%.5f Write(MB):%.5f\n", float64(stats.IORead)/1048576.0, float64(stats.IOWrite)/1048576.0)
|
||||
message += fmt.Sprintf("BlockCache(MB):%.5f FileCache:%d\n", float64(stats.BlockCacheSize)/1048576.0, stats.OpenedTablesCount)
|
||||
message += fmt.Sprintf("MemoryCompaction:%d Level0Compaction:%d NonLevel0Compaction:%d SeekCompaction:%d\n", stats.MemComp, stats.Level0Comp, stats.NonLevel0Comp, stats.SeekComp)
|
||||
message += fmt.Sprintf("WriteDelayCount:%d WriteDelayDuration:%s Paused:%t\n", stats.WriteDelayCount, common.PrettyDuration(stats.WriteDelayDuration), stats.WritePaused)
|
||||
message += fmt.Sprintf("Snapshots:%d Iterators:%d\n", stats.AliveSnapshots, stats.AliveIterators)
|
||||
return message, nil
|
||||
}
|
||||
|
||||
// Compact flattens the underlying data store for the given key range. In essence,
|
||||
|
|
|
|||
|
|
@ -182,9 +182,9 @@ func (db *Database) NewSnapshot() (ethdb.Snapshot, error) {
|
|||
return newSnapshot(db), nil
|
||||
}
|
||||
|
||||
// Stat returns a particular internal stat of the database.
|
||||
func (db *Database) Stat(property string) (string, error) {
|
||||
return "", errors.New("unknown property")
|
||||
// Stat returns the statistic data of the database.
|
||||
func (db *Database) Stat() (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Compact is not supported on a memory database, but there's no need either as
|
||||
|
|
|
|||
|
|
@ -416,10 +416,8 @@ func upperBound(prefix []byte) (limit []byte) {
|
|||
}
|
||||
|
||||
// Stat returns the internal metrics of Pebble in a text format. It's a developer
|
||||
// method to read everything there is to read independent of Pebble version.
|
||||
//
|
||||
// The property is unused in Pebble as there's only one thing to retrieve.
|
||||
func (d *Database) Stat(property string) (string, error) {
|
||||
// method to read everything there is to read, independent of Pebble version.
|
||||
func (d *Database) Stat() (string, error) {
|
||||
return d.db.Metrics().String(), nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -126,8 +126,8 @@ func (db *Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator {
|
|||
panic("not supported")
|
||||
}
|
||||
|
||||
func (db *Database) Stat(property string) (string, error) {
|
||||
panic("not supported")
|
||||
func (db *Database) Stat() (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (db *Database) AncientDatadir() (string, error) {
|
||||
|
|
|
|||
17
go.mod
17
go.mod
|
|
@ -13,7 +13,7 @@ require (
|
|||
github.com/btcsuite/btcd/btcec/v2 v2.2.0
|
||||
github.com/cespare/cp v0.1.0
|
||||
github.com/cloudflare/cloudflare-go v0.79.0
|
||||
github.com/cockroachdb/pebble v1.1.0
|
||||
github.com/cockroachdb/pebble v1.1.1
|
||||
github.com/consensys/gnark-crypto v0.12.1
|
||||
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c
|
||||
github.com/crate-crypto/go-kzg-4844 v1.0.0
|
||||
|
|
@ -40,7 +40,7 @@ require (
|
|||
github.com/hashicorp/go-bexpr v0.1.10
|
||||
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3
|
||||
github.com/holiman/uint256 v1.2.4
|
||||
github.com/holiman/uint256 v1.3.0
|
||||
github.com/huin/goupnp v1.3.0
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.4.0
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
||||
|
|
@ -61,18 +61,20 @@ require (
|
|||
github.com/rs/cors v1.7.0
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
|
||||
github.com/status-im/keycard-go v0.2.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/supranational/blst v0.3.11
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
|
||||
github.com/tyler-smith/go-bip39 v1.1.0
|
||||
github.com/urfave/cli/v2 v2.25.7
|
||||
go.uber.org/automaxprocs v1.5.2
|
||||
golang.org/x/crypto v0.22.0
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
|
||||
golang.org/x/sync v0.7.0
|
||||
golang.org/x/sys v0.20.0
|
||||
golang.org/x/text v0.14.0
|
||||
golang.org/x/time v0.5.0
|
||||
golang.org/x/tools v0.20.0
|
||||
google.golang.org/protobuf v1.33.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
|
@ -94,7 +96,8 @@ require (
|
|||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.10.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cockroachdb/errors v1.11.1 // indirect
|
||||
github.com/cockroachdb/errors v1.11.3 // indirect
|
||||
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
||||
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
|
||||
|
|
@ -104,7 +107,7 @@ require (
|
|||
github.com/deepmap/oapi-codegen v1.6.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.7.0 // indirect
|
||||
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect
|
||||
github.com/getsentry/sentry-go v0.18.0 // indirect
|
||||
github.com/getsentry/sentry-go v0.27.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
|
|
@ -115,7 +118,7 @@ require (
|
|||
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
|
||||
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/klauspost/compress v1.15.15 // indirect
|
||||
github.com/klauspost/compress v1.16.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
|
|
@ -139,10 +142,8 @@ require (
|
|||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/net v0.24.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
rsc.io/tmplfunc v0.0.3 // indirect
|
||||
)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue