Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e3b149be0 | ||
|
|
6cf2e921a7 | ||
|
|
564db9a95f | ||
|
|
051493d9bf | ||
|
|
df02799543 | ||
|
|
67ac5f0ae7 | ||
|
|
08f6a2a89d | ||
|
|
5395362e0f | ||
|
|
1bf1168432 | ||
|
|
b80f05bde2 | ||
|
|
e14043db71 | ||
|
|
02796f6bee | ||
|
|
f7661a662a | ||
|
|
bb4ac2d396 | ||
|
|
5ed08c4735 | ||
|
|
a54d91ac5a | ||
|
|
78429f7733 | ||
|
|
1e3177de22 | ||
|
|
41af42e97c | ||
|
|
cb1f6bdbc8 | ||
|
|
39be753bf5 | ||
|
|
77e33e5a49 | ||
|
|
4688d3c8f4 | ||
|
|
544e4a700b | ||
|
|
5bc2ef984f | ||
|
|
87186148e0 | ||
|
|
4c23fe97c5 | ||
|
|
d865a5d6ae | ||
|
|
27e59827d8 | ||
|
|
403cac71eb | ||
|
|
010189538e | ||
|
|
19f74fa3c0 | ||
|
|
cd31f2dee2 | ||
|
|
e1b98f49a5 | ||
|
|
2bb622ce40 | ||
|
|
98b0ea62b5 | ||
|
|
2ea48f8a22 | ||
|
|
2ad150d986 | ||
|
|
c155c8e179 | ||
|
|
ee530c0d5a | ||
|
|
b3ae073488 | ||
|
|
09a9ccdbce | ||
|
|
a36c68f12c | ||
|
|
f6a7cc68d5 | ||
|
|
73b01f40ce | ||
|
|
f86f048646 | ||
|
|
4034c675be | ||
|
|
fe01a2f63b | ||
|
|
2f20fd31ee | ||
|
|
6d2d126100 | ||
|
|
90d25514af | ||
|
|
7d4db69607 | ||
|
|
13ef21d467 | ||
|
|
ba4267fcac | ||
|
|
41dee2623e | ||
|
|
4519054816 | ||
|
|
c02334be1e | ||
|
|
165268430c | ||
|
|
a43efceaf2 | ||
|
|
4ec4235fc4 | ||
|
|
e1e2781105 | ||
|
|
2166c86041 | ||
|
|
1db978ca6b | ||
|
|
7c749c947a | ||
|
|
15e5e6176b | ||
|
|
a0d63bc69a | ||
|
|
6428663faf | ||
|
|
b40c10916c |
57
.travis.yml
57
.travis.yml
@@ -5,7 +5,6 @@ jobs:
|
||||
allow_failures:
|
||||
- stage: build
|
||||
os: osx
|
||||
go: 1.17.x
|
||||
env:
|
||||
- azure-osx
|
||||
|
||||
@@ -58,30 +57,6 @@ jobs:
|
||||
script:
|
||||
- go run build/ci.go docker -image -manifest amd64,arm64 -upload ethereum/client-go
|
||||
|
||||
# This builder does the Ubuntu PPA upload
|
||||
- stage: build
|
||||
if: type = push
|
||||
os: linux
|
||||
dist: bionic
|
||||
go: 1.20.x
|
||||
env:
|
||||
- ubuntu-ppa
|
||||
- GO111MODULE=on
|
||||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- devscripts
|
||||
- debhelper
|
||||
- dput
|
||||
- fakeroot
|
||||
- python-bzrlib
|
||||
- python-paramiko
|
||||
script:
|
||||
- echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts
|
||||
- go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>"
|
||||
|
||||
# This builder does the Linux Azure uploads
|
||||
- stage: build
|
||||
if: type = push
|
||||
@@ -141,7 +116,7 @@ jobs:
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
script:
|
||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||
- go run build/ci.go test $TEST_PACKAGES
|
||||
|
||||
- stage: build
|
||||
if: type = pull_request
|
||||
@@ -152,7 +127,7 @@ jobs:
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
script:
|
||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||
- go run build/ci.go test $TEST_PACKAGES
|
||||
|
||||
- stage: build
|
||||
os: linux
|
||||
@@ -161,7 +136,31 @@ jobs:
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
script:
|
||||
- go run build/ci.go test -coverage $TEST_PACKAGES
|
||||
- go run build/ci.go test $TEST_PACKAGES
|
||||
|
||||
# This builder does the Ubuntu PPA nightly uploads
|
||||
- stage: build
|
||||
if: type = cron
|
||||
os: linux
|
||||
dist: bionic
|
||||
go: 1.20.x
|
||||
env:
|
||||
- ubuntu-ppa
|
||||
- GO111MODULE=on
|
||||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- devscripts
|
||||
- debhelper
|
||||
- dput
|
||||
- fakeroot
|
||||
- python-bzrlib
|
||||
- python-paramiko
|
||||
script:
|
||||
- echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts
|
||||
- go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>"
|
||||
|
||||
# This builder does the Azure archive purges to avoid accumulating junk
|
||||
- stage: build
|
||||
@@ -186,5 +185,5 @@ jobs:
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
script:
|
||||
- go run build/ci.go test -race -coverage $TEST_PACKAGES
|
||||
- go run build/ci.go test -race $TEST_PACKAGES
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ archives are published at https://geth.ethereum.org/downloads/.
|
||||
|
||||
For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth).
|
||||
|
||||
Building `geth` requires both a Go (version 1.18 or later) and a C compiler. You can install
|
||||
Building `geth` requires both a Go (version 1.19 or later) and a C compiler. You can install
|
||||
them using your favourite package manager. Once the dependencies are installed, run
|
||||
|
||||
```shell
|
||||
|
||||
@@ -95,7 +95,10 @@ func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.Genesis
|
||||
backend.filterSystem = filters.NewFilterSystem(filterBackend, filters.Config{})
|
||||
backend.events = filters.NewEventSystem(backend.filterSystem, false)
|
||||
|
||||
backend.rollback(blockchain.CurrentBlock())
|
||||
header := backend.blockchain.CurrentBlock()
|
||||
block := backend.blockchain.GetBlock(header.Hash(), header.Number.Uint64())
|
||||
|
||||
backend.rollback(block)
|
||||
return backend
|
||||
}
|
||||
|
||||
@@ -135,7 +138,10 @@ func (b *SimulatedBackend) Rollback() {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
b.rollback(b.blockchain.CurrentBlock())
|
||||
header := b.blockchain.CurrentBlock()
|
||||
block := b.blockchain.GetBlock(header.Hash(), header.Number.Uint64())
|
||||
|
||||
b.rollback(block)
|
||||
}
|
||||
|
||||
func (b *SimulatedBackend) rollback(parent *types.Block) {
|
||||
@@ -174,7 +180,7 @@ func (b *SimulatedBackend) Fork(ctx context.Context, parent common.Hash) error {
|
||||
|
||||
// stateByBlockNumber retrieves a state by a given blocknumber.
|
||||
func (b *SimulatedBackend) stateByBlockNumber(ctx context.Context, blockNumber *big.Int) (*state.StateDB, error) {
|
||||
if blockNumber == nil || blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) == 0 {
|
||||
if blockNumber == nil || blockNumber.Cmp(b.blockchain.CurrentBlock().Number) == 0 {
|
||||
return b.blockchain.State()
|
||||
}
|
||||
block, err := b.blockByNumber(ctx, blockNumber)
|
||||
@@ -303,7 +309,7 @@ func (b *SimulatedBackend) BlockByNumber(ctx context.Context, number *big.Int) (
|
||||
// (associated with its hash) if found without Lock.
|
||||
func (b *SimulatedBackend) blockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
|
||||
if number == nil || number.Cmp(b.pendingBlock.Number()) == 0 {
|
||||
return b.blockchain.CurrentBlock(), nil
|
||||
return b.blockByHash(ctx, b.blockchain.CurrentBlock().Hash())
|
||||
}
|
||||
|
||||
block := b.blockchain.GetBlockByNumber(uint64(number.Int64()))
|
||||
@@ -431,7 +437,7 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallM
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
||||
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number) != 0 {
|
||||
return nil, errBlockNumberUnsupported
|
||||
}
|
||||
stateDB, err := b.blockchain.State()
|
||||
@@ -455,7 +461,7 @@ func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereu
|
||||
defer b.mu.Unlock()
|
||||
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
|
||||
|
||||
res, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
|
||||
res, err := b.callContract(ctx, call, b.pendingBlock.Header(), b.pendingState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -549,7 +555,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
||||
call.Gas = gas
|
||||
|
||||
snapshot := b.pendingState.Snapshot()
|
||||
res, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
|
||||
res, err := b.callContract(ctx, call, b.pendingBlock.Header(), b.pendingState)
|
||||
b.pendingState.RevertToSnapshot(snapshot)
|
||||
|
||||
if err != nil {
|
||||
@@ -599,7 +605,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
||||
|
||||
// callContract implements common code between normal and pending contract calls.
|
||||
// state is modified during execution, make sure to copy it if necessary.
|
||||
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, stateDB *state.StateDB) (*core.ExecutionResult, error) {
|
||||
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, header *types.Header, stateDB *state.StateDB) (*core.ExecutionResult, error) {
|
||||
// Gas prices post 1559 need to be initialized
|
||||
if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) {
|
||||
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
||||
@@ -638,20 +644,33 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
||||
if call.Value == nil {
|
||||
call.Value = new(big.Int)
|
||||
}
|
||||
|
||||
// Set infinite balance to the fake caller account.
|
||||
from := stateDB.GetOrNewStateObject(call.From)
|
||||
from.SetBalance(math.MaxBig256)
|
||||
// Execute the call.
|
||||
msg := callMsg{call}
|
||||
|
||||
txContext := core.NewEVMTxContext(msg)
|
||||
evmContext := core.NewEVMBlockContext(block.Header(), b.blockchain, nil)
|
||||
// Execute the call.
|
||||
msg := &core.Message{
|
||||
From: call.From,
|
||||
To: call.To,
|
||||
Value: call.Value,
|
||||
GasLimit: call.Gas,
|
||||
GasPrice: call.GasPrice,
|
||||
GasFeeCap: call.GasFeeCap,
|
||||
GasTipCap: call.GasTipCap,
|
||||
Data: call.Data,
|
||||
AccessList: call.AccessList,
|
||||
SkipAccountChecks: true,
|
||||
}
|
||||
|
||||
// Create a new environment which holds all relevant information
|
||||
// about the transaction and calling mechanisms.
|
||||
txContext := core.NewEVMTxContext(msg)
|
||||
evmContext := core.NewEVMBlockContext(header, b.blockchain, nil)
|
||||
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
|
||||
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
|
||||
|
||||
return core.NewStateTransition(vmEnv, msg, gasPool).TransitionDb()
|
||||
return core.ApplyMessage(vmEnv, msg, gasPool)
|
||||
}
|
||||
|
||||
// SendTransaction updates the pending block to include the given transaction.
|
||||
@@ -815,23 +834,6 @@ func (b *SimulatedBackend) Blockchain() *core.BlockChain {
|
||||
return b.blockchain
|
||||
}
|
||||
|
||||
// callMsg implements core.Message to allow passing it as a transaction simulator.
|
||||
type callMsg struct {
|
||||
ethereum.CallMsg
|
||||
}
|
||||
|
||||
func (m callMsg) From() common.Address { return m.CallMsg.From }
|
||||
func (m callMsg) Nonce() uint64 { return 0 }
|
||||
func (m callMsg) IsFake() bool { return true }
|
||||
func (m callMsg) To() *common.Address { return m.CallMsg.To }
|
||||
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
||||
func (m callMsg) GasFeeCap() *big.Int { return m.CallMsg.GasFeeCap }
|
||||
func (m callMsg) GasTipCap() *big.Int { return m.CallMsg.GasTipCap }
|
||||
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
|
||||
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
|
||||
func (m callMsg) Data() []byte { return m.CallMsg.Data }
|
||||
func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList }
|
||||
|
||||
// filterBackend implements filters.Backend to support filtering for logs without
|
||||
// taking bloom-bits acceleration structures into account.
|
||||
type filterBackend struct {
|
||||
@@ -854,15 +856,9 @@ func (fb *filterBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNum
|
||||
case rpc.LatestBlockNumber:
|
||||
return fb.bc.CurrentHeader(), nil
|
||||
case rpc.FinalizedBlockNumber:
|
||||
if block := fb.bc.CurrentFinalizedBlock(); block != nil {
|
||||
return block.Header(), nil
|
||||
}
|
||||
return nil, errors.New("finalized block not found")
|
||||
return fb.bc.CurrentFinalBlock(), nil
|
||||
case rpc.SafeBlockNumber:
|
||||
if block := fb.bc.CurrentSafeBlock(); block != nil {
|
||||
return block.Header(), nil
|
||||
}
|
||||
return nil, errors.New("safe block not found")
|
||||
return fb.bc.CurrentSafeBlock(), nil
|
||||
default:
|
||||
return fb.bc.GetHeaderByNumber(uint64(number.Int64())), nil
|
||||
}
|
||||
|
||||
@@ -1189,7 +1189,7 @@ func TestFork(t *testing.T) {
|
||||
sim.Commit()
|
||||
}
|
||||
// 3.
|
||||
if sim.blockchain.CurrentBlock().NumberU64() != uint64(n) {
|
||||
if sim.blockchain.CurrentBlock().Number.Uint64() != uint64(n) {
|
||||
t.Error("wrong chain length")
|
||||
}
|
||||
// 4.
|
||||
@@ -1199,7 +1199,7 @@ func TestFork(t *testing.T) {
|
||||
sim.Commit()
|
||||
}
|
||||
// 6.
|
||||
if sim.blockchain.CurrentBlock().NumberU64() != uint64(n+1) {
|
||||
if sim.blockchain.CurrentBlock().Number.Uint64() != uint64(n+1) {
|
||||
t.Error("wrong chain length")
|
||||
}
|
||||
}
|
||||
@@ -1344,7 +1344,7 @@ func TestCommitReturnValue(t *testing.T) {
|
||||
sim := simTestBackend(testAddr)
|
||||
defer sim.Close()
|
||||
|
||||
startBlockHeight := sim.blockchain.CurrentBlock().NumberU64()
|
||||
startBlockHeight := sim.blockchain.CurrentBlock().Number.Uint64()
|
||||
|
||||
// Test if Commit returns the correct block hash
|
||||
h1 := sim.Commit()
|
||||
|
||||
@@ -59,6 +59,8 @@ const (
|
||||
ledgerP1InitTransactionData ledgerParam1 = 0x00 // First transaction data block for signing
|
||||
ledgerP1ContTransactionData ledgerParam1 = 0x80 // Subsequent transaction data block for signing
|
||||
ledgerP2DiscardAddressChainCode ledgerParam2 = 0x00 // Do not return the chain code along with the address
|
||||
|
||||
ledgerEip155Size int = 3 // Size of the EIP-155 chain_id,r,s in unsigned transactions
|
||||
)
|
||||
|
||||
// errLedgerReplyInvalidHeader is the error message returned by a Ledger data exchange
|
||||
@@ -347,9 +349,15 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
|
||||
op = ledgerP1InitTransactionData
|
||||
reply []byte
|
||||
)
|
||||
|
||||
// Chunk size selection to mitigate an underlying RLP deserialization issue on the ledger app.
|
||||
// https://github.com/LedgerHQ/app-ethereum/issues/409
|
||||
chunk := 255
|
||||
for ; len(payload)%chunk <= ledgerEip155Size; chunk-- {
|
||||
}
|
||||
|
||||
for len(payload) > 0 {
|
||||
// Calculate the size of the next data chunk
|
||||
chunk := 255
|
||||
if chunk > len(payload) {
|
||||
chunk = len(payload)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ for:
|
||||
- go run build/ci.go lint
|
||||
- go run build/ci.go install -dlgo
|
||||
test_script:
|
||||
- go run build/ci.go test -dlgo -coverage
|
||||
- go run build/ci.go test -dlgo
|
||||
|
||||
# linux/386 is disabled.
|
||||
- matrix:
|
||||
@@ -54,4 +54,4 @@ for:
|
||||
- go run build/ci.go archive -arch %GETH_ARCH% -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
|
||||
- go run build/ci.go nsis -arch %GETH_ARCH% -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
|
||||
test_script:
|
||||
- go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC% -coverage
|
||||
- go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC%
|
||||
|
||||
@@ -74,12 +74,11 @@ var (
|
||||
// - newPayloadV1: if the payload was accepted, but not processed (side chain)
|
||||
ACCEPTED = "ACCEPTED"
|
||||
|
||||
INVALIDBLOCKHASH = "INVALID_BLOCK_HASH"
|
||||
|
||||
GenericServerError = &EngineAPIError{code: -32000, msg: "Server error"}
|
||||
UnknownPayload = &EngineAPIError{code: -38001, msg: "Unknown payload"}
|
||||
InvalidForkChoiceState = &EngineAPIError{code: -38002, msg: "Invalid forkchoice state"}
|
||||
InvalidPayloadAttributes = &EngineAPIError{code: -38003, msg: "Invalid payload attributes"}
|
||||
TooLargeRequest = &EngineAPIError{code: -38004, msg: "Too large request"}
|
||||
InvalidParams = &EngineAPIError{code: -32602, msg: "Invalid parameters"}
|
||||
|
||||
STATUS_INVALID = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: INVALID}, PayloadID: nil}
|
||||
|
||||
@@ -233,5 +233,5 @@ func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutionPayloadE
|
||||
// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1
|
||||
type ExecutionPayloadBodyV1 struct {
|
||||
TransactionData []hexutil.Bytes `json:"transactions"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"`
|
||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
# This file contains sha256 checksums of optional build dependencies.
|
||||
|
||||
b5c1a3af52c385a6d1c76aed5361cf26459023980d0320de7658bae3915831a2 go1.20.1.src.tar.gz
|
||||
a300a45e801ab459f3008aae5bb9efbe9a6de9bcd12388f5ca9bbd14f70236de go1.20.1.darwin-amd64.tar.gz
|
||||
f1a8e06c7f1ba1c008313577f3f58132eb166a41ceb95ce6e9af30bc5a3efca4 go1.20.1.darwin-arm64.tar.gz
|
||||
57d80349dc4fbf692f8cd85a5971f97841aedafcf211e367e59d3ae812292660 go1.20.1.freebsd-386.tar.gz
|
||||
6e124d54d5850a15fdb15754f782986f06af23c5ddb6690849417b9c74f05f98 go1.20.1.freebsd-amd64.tar.gz
|
||||
3a7345036ebd92455b653e4b4f6aaf4f7e1f91f4ced33b23d7059159cec5f4d7 go1.20.1.linux-386.tar.gz
|
||||
000a5b1fca4f75895f78befeb2eecf10bfff3c428597f3f1e69133b63b911b02 go1.20.1.linux-amd64.tar.gz
|
||||
5e5e2926733595e6f3c5b5ad1089afac11c1490351855e87849d0e7702b1ec2e go1.20.1.linux-arm64.tar.gz
|
||||
e4edc05558ab3657ba3dddb909209463cee38df9c1996893dd08cde274915003 go1.20.1.linux-armv6l.tar.gz
|
||||
85cfd4b89b48c94030783b6e9e619e35557862358b846064636361421d0b0c52 go1.20.1.linux-ppc64le.tar.gz
|
||||
ba3a14381ed4538216dec3ea72b35731750597edd851cece1eb120edf7d60149 go1.20.1.linux-s390x.tar.gz
|
||||
61259b5a346193e30b7b3c3f8d108062db25bbb80cf290ee251eeb855965f6ee go1.20.1.windows-386.zip
|
||||
3b493969196a6de8d9762d09f5bc5ae7a3e5814b0cfbf9cc26838c2bc1314f9c go1.20.1.windows-amd64.zip
|
||||
62d14ddb44bcda27c9b1f5ad9ffd4463013374ed325d762417e2adefd59a802f go1.20.1.windows-arm64.zip
|
||||
4d0e2850d197b4ddad3bdb0196300179d095bb3aefd4dfbc3b36702c3728f8ab go1.20.2.src.tar.gz
|
||||
c93b8ced9517d07e1cd4c362c6e2d5242cb139e29b417a328fbf19aded08764c go1.20.2.darwin-amd64.tar.gz
|
||||
7343c87f19e79c0063532e82e1c4d6f42175a32d99f7a4d15e658e88bf97f885 go1.20.2.darwin-arm64.tar.gz
|
||||
14f9be2004e042b3a64d0facb0c020756a9084a5c7333e33b0752b393b6016ea go1.20.2.freebsd-386.tar.gz
|
||||
b41b67b4f1b56797a7cecf6ee7f47fcf4f93960b2788a3683c07dd009d30b2a4 go1.20.2.freebsd-amd64.tar.gz
|
||||
ee240ed33ae57504c41f04c12236aeaa17fbeb6ea9fcd096cd9dc7a89d10d4db go1.20.2.linux-386.tar.gz
|
||||
4eaea32f59cde4dc635fbc42161031d13e1c780b87097f4b4234cfce671f1768 go1.20.2.linux-amd64.tar.gz
|
||||
78d632915bb75e9a6356a47a42625fd1a785c83a64a643fedd8f61e31b1b3bef go1.20.2.linux-arm64.tar.gz
|
||||
d79d56bafd6b52b8d8cbe3f8e967caaac5383a23d7a4fa9ac0e89778cd16a076 go1.20.2.linux-armv6l.tar.gz
|
||||
850564ddb760cb703db63bf20182dc4407abd2ff090a95fa66d6634d172fd095 go1.20.2.linux-ppc64le.tar.gz
|
||||
8da24c5c4205fe8115f594237e5db7bcb1d23df67bc1fa9a999954b1976896e8 go1.20.2.linux-s390x.tar.gz
|
||||
31838b291117495bbb93683603e98d5118bfabd2eb318b4d07540bfd524bab86 go1.20.2.windows-386.zip
|
||||
fe439f0e438f7555a7f5f7194ddb6f4a07b0de1fa414385d19f2aeb26d9f43db go1.20.2.windows-amd64.zip
|
||||
ac5010c8b8b22849228a8dea698d58b9c7be2195d30c6d778cce0f709858fa64 go1.20.2.windows-arm64.zip
|
||||
|
||||
fba08acc4027f69f07cef48fbff70b8a7ecdfaa1c2aba9ad3fb31d60d9f5d4bc golangci-lint-1.51.1-darwin-amd64.tar.gz
|
||||
75b8f0ff3a4e68147156be4161a49d4576f1be37a0b506473f8c482140c1e7f2 golangci-lint-1.51.1-darwin-arm64.tar.gz
|
||||
@@ -41,3 +41,6 @@ c4f58b7e227b9fd41f0e9310dc83f4a4e7d026598e2f6e95b78761081a6d9bd2 golangci-lint-
|
||||
eb57f9bcb56646f2e3d6ccaf02ec227815fb05077b2e0b1bf9e755805acdc2b9 golangci-lint-1.51.1-windows-arm64.zip
|
||||
bce02f7232723cb727755ee11f168a700a00896a25d37f87c4b173bce55596b4 golangci-lint-1.51.1-windows-armv6.zip
|
||||
cf6403f84707ce8c98664736772271bc8874f2e760c2fd0f00cf3e85963507e9 golangci-lint-1.51.1-windows-armv7.zip
|
||||
|
||||
# This is the builder on PPA that will build Go itself (inception-y), don't modify!
|
||||
d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz
|
||||
|
||||
49
build/ci.go
49
build/ci.go
@@ -128,7 +128,7 @@ var (
|
||||
"focal": "golang-go", // EOL: 04/2030
|
||||
"jammy": "golang-go", // EOL: 04/2032
|
||||
"kinetic": "golang-go", // EOL: 07/2023
|
||||
//"lunar": "golang-go", // EOL: 01/2024
|
||||
"lunar": "golang-go", // EOL: 01/2024
|
||||
}
|
||||
|
||||
debGoBootPaths = map[string]string{
|
||||
@@ -136,10 +136,18 @@ var (
|
||||
"golang-go": "/usr/lib/go",
|
||||
}
|
||||
|
||||
// This is the version of go that will be downloaded by
|
||||
// This is the version of Go that will be downloaded by
|
||||
//
|
||||
// go run ci.go install -dlgo
|
||||
dlgoVersion = "1.20.1"
|
||||
dlgoVersion = "1.20.2"
|
||||
|
||||
// This is the version of Go that will be used to bootstrap the PPA builder.
|
||||
//
|
||||
// This version is fine to be old and full of security holes, we just use it
|
||||
// to build the latest Go. Don't change it. If it ever becomes insufficient,
|
||||
// we need to switch over to a recursive builder to jumpt across supported
|
||||
// versions.
|
||||
gobootVersion = "1.19.6"
|
||||
)
|
||||
|
||||
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
|
||||
@@ -655,10 +663,11 @@ func doDebianSource(cmdline []string) {
|
||||
gpg.Stdin = bytes.NewReader(key)
|
||||
build.MustRun(gpg)
|
||||
}
|
||||
|
||||
// Download and verify the Go source package.
|
||||
gobundle := downloadGoSources(*cachedir)
|
||||
|
||||
// Download and verify the Go source packages.
|
||||
var (
|
||||
gobootbundle = downloadGoBootstrapSources(*cachedir)
|
||||
gobundle = downloadGoSources(*cachedir)
|
||||
)
|
||||
// Download all the dependencies needed to build the sources and run the ci script
|
||||
srcdepfetch := tc.Go("mod", "download")
|
||||
srcdepfetch.Env = append(srcdepfetch.Env, "GOPATH="+filepath.Join(*workdir, "modgopath"))
|
||||
@@ -675,12 +684,19 @@ func doDebianSource(cmdline []string) {
|
||||
meta := newDebMetadata(distro, goboot, *signer, env, now, pkg.Name, pkg.Version, pkg.Executables)
|
||||
pkgdir := stageDebianSource(*workdir, meta)
|
||||
|
||||
// Add Go source code
|
||||
// Add bootstrapper Go source code
|
||||
if err := build.ExtractArchive(gobootbundle, pkgdir); err != nil {
|
||||
log.Fatalf("Failed to extract bootstrapper Go sources: %v", err)
|
||||
}
|
||||
if err := os.Rename(filepath.Join(pkgdir, "go"), filepath.Join(pkgdir, ".goboot")); err != nil {
|
||||
log.Fatalf("Failed to rename bootstrapper Go source folder: %v", err)
|
||||
}
|
||||
// Add builder Go source code
|
||||
if err := build.ExtractArchive(gobundle, pkgdir); err != nil {
|
||||
log.Fatalf("Failed to extract Go sources: %v", err)
|
||||
log.Fatalf("Failed to extract builder Go sources: %v", err)
|
||||
}
|
||||
if err := os.Rename(filepath.Join(pkgdir, "go"), filepath.Join(pkgdir, ".go")); err != nil {
|
||||
log.Fatalf("Failed to rename Go source folder: %v", err)
|
||||
log.Fatalf("Failed to rename builder Go source folder: %v", err)
|
||||
}
|
||||
// Add all dependency modules in compressed form
|
||||
os.MkdirAll(filepath.Join(pkgdir, ".mod", "cache"), 0755)
|
||||
@@ -709,6 +725,19 @@ func doDebianSource(cmdline []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// downloadGoBootstrapSources downloads the Go source tarball that will be used
|
||||
// to bootstrap the builder Go.
|
||||
func downloadGoBootstrapSources(cachedir string) string {
|
||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||
file := fmt.Sprintf("go%s.src.tar.gz", gobootVersion)
|
||||
url := "https://dl.google.com/go/" + file
|
||||
dst := filepath.Join(cachedir, file)
|
||||
if err := csdb.DownloadFile(url, dst); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// downloadGoSources downloads the Go source tarball.
|
||||
func downloadGoSources(cachedir string) string {
|
||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||
|
||||
@@ -16,7 +16,11 @@ override_dh_auto_build:
|
||||
# We can't download a fresh Go within Launchpad, so we're shipping and building
|
||||
# one on the fly. However, we can't build it inside the go-ethereum folder as
|
||||
# bootstrapping clashes with go modules, so build in a sibling folder.
|
||||
(mv .go ../ && cd ../.go/src && ./make.bash)
|
||||
#
|
||||
# We're also shipping the bootstrapper as of Go 1.20 as it had minimum version
|
||||
# requirements opposed to older versions of Go.
|
||||
(mv .goboot ../ && cd ../.goboot/src && ./make.bash)
|
||||
(mv .go ../ && cd ../.go/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot ./make.bash)
|
||||
|
||||
# We can't download external go modules within Launchpad, so we're shipping the
|
||||
# entire dependency source cache with go-ethereum.
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
@@ -34,6 +36,7 @@ type crawler struct {
|
||||
|
||||
// settings
|
||||
revalidateInterval time.Duration
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -67,7 +70,7 @@ func newCrawler(input nodeSet, disc resolver, iters ...enode.Iterator) *crawler
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *crawler) run(timeout time.Duration) nodeSet {
|
||||
func (c *crawler) run(timeout time.Duration, nthreads int) nodeSet {
|
||||
var (
|
||||
timeoutTimer = time.NewTimer(timeout)
|
||||
timeoutCh <-chan time.Time
|
||||
@@ -75,35 +78,51 @@ func (c *crawler) run(timeout time.Duration) nodeSet {
|
||||
doneCh = make(chan enode.Iterator, len(c.iters))
|
||||
liveIters = len(c.iters)
|
||||
)
|
||||
if nthreads < 1 {
|
||||
nthreads = 1
|
||||
}
|
||||
defer timeoutTimer.Stop()
|
||||
defer statusTicker.Stop()
|
||||
for _, it := range c.iters {
|
||||
go c.runIterator(doneCh, it)
|
||||
}
|
||||
|
||||
var (
|
||||
added int
|
||||
updated int
|
||||
skipped int
|
||||
recent int
|
||||
removed int
|
||||
added uint64
|
||||
updated uint64
|
||||
skipped uint64
|
||||
recent uint64
|
||||
removed uint64
|
||||
wg sync.WaitGroup
|
||||
)
|
||||
wg.Add(nthreads)
|
||||
for i := 0; i < nthreads; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case n := <-c.ch:
|
||||
switch c.updateNode(n) {
|
||||
case nodeSkipIncompat:
|
||||
atomic.AddUint64(&skipped, 1)
|
||||
case nodeSkipRecent:
|
||||
atomic.AddUint64(&recent, 1)
|
||||
case nodeRemoved:
|
||||
atomic.AddUint64(&removed, 1)
|
||||
case nodeAdded:
|
||||
atomic.AddUint64(&added, 1)
|
||||
default:
|
||||
atomic.AddUint64(&updated, 1)
|
||||
}
|
||||
case <-c.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case n := <-c.ch:
|
||||
switch c.updateNode(n) {
|
||||
case nodeSkipIncompat:
|
||||
skipped++
|
||||
case nodeSkipRecent:
|
||||
recent++
|
||||
case nodeRemoved:
|
||||
removed++
|
||||
case nodeAdded:
|
||||
added++
|
||||
default:
|
||||
updated++
|
||||
}
|
||||
case it := <-doneCh:
|
||||
if it == c.inputIter {
|
||||
// Enable timeout when we're done revalidating the input nodes.
|
||||
@@ -119,8 +138,11 @@ loop:
|
||||
break loop
|
||||
case <-statusTicker.C:
|
||||
log.Info("Crawling in progress",
|
||||
"added", added, "updated", updated, "removed", removed,
|
||||
"ignored(recent)", recent, "ignored(incompatible)", skipped)
|
||||
"added", atomic.LoadUint64(&added),
|
||||
"updated", atomic.LoadUint64(&updated),
|
||||
"removed", atomic.LoadUint64(&removed),
|
||||
"ignored(recent)", atomic.LoadUint64(&removed),
|
||||
"ignored(incompatible)", atomic.LoadUint64(&skipped))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +153,7 @@ loop:
|
||||
for ; liveIters > 0; liveIters-- {
|
||||
<-doneCh
|
||||
}
|
||||
wg.Wait()
|
||||
return c.output
|
||||
}
|
||||
|
||||
@@ -148,7 +171,9 @@ func (c *crawler) runIterator(done chan<- enode.Iterator, it enode.Iterator) {
|
||||
// updateNode updates the info about the given node, and returns a status
|
||||
// about what changed
|
||||
func (c *crawler) updateNode(n *enode.Node) int {
|
||||
c.mu.RLock()
|
||||
node, ok := c.output[n.ID()]
|
||||
c.mu.RUnlock()
|
||||
|
||||
// Skip validation of recently-seen nodes.
|
||||
if ok && time.Since(node.LastCheck) < c.revalidateInterval {
|
||||
@@ -156,10 +181,9 @@ func (c *crawler) updateNode(n *enode.Node) int {
|
||||
}
|
||||
|
||||
// Request the node record.
|
||||
nn, err := c.disc.RequestENR(n)
|
||||
node.LastCheck = truncNow()
|
||||
status := nodeUpdated
|
||||
if err != nil {
|
||||
node.LastCheck = truncNow()
|
||||
if nn, err := c.disc.RequestENR(n); err != nil {
|
||||
if node.Score == 0 {
|
||||
// Node doesn't implement EIP-868.
|
||||
log.Debug("Skipping node", "id", n.ID())
|
||||
@@ -176,8 +200,9 @@ func (c *crawler) updateNode(n *enode.Node) int {
|
||||
}
|
||||
node.LastResponse = node.LastCheck
|
||||
}
|
||||
|
||||
// Store/update node in output set.
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if node.Score <= 0 {
|
||||
log.Debug("Removing node", "id", n.ID())
|
||||
delete(c.output, n.ID())
|
||||
|
||||
@@ -78,7 +78,7 @@ var (
|
||||
Name: "crawl",
|
||||
Usage: "Updates a nodes.json file with random nodes found in the DHT",
|
||||
Action: discv4Crawl,
|
||||
Flags: flags.Merge(discoveryNodeFlags, []cli.Flag{crawlTimeoutFlag}),
|
||||
Flags: flags.Merge(discoveryNodeFlags, []cli.Flag{crawlTimeoutFlag, crawlParallelismFlag}),
|
||||
}
|
||||
discv4TestCommand = &cli.Command{
|
||||
Name: "test",
|
||||
@@ -120,6 +120,11 @@ var (
|
||||
Usage: "Time limit for the crawl.",
|
||||
Value: 30 * time.Minute,
|
||||
}
|
||||
crawlParallelismFlag = &cli.IntFlag{
|
||||
Name: "parallel",
|
||||
Usage: "How many parallel discoveries to attempt.",
|
||||
Value: 16,
|
||||
}
|
||||
remoteEnodeFlag = &cli.StringFlag{
|
||||
Name: "remote",
|
||||
Usage: "Enode of the remote node under test",
|
||||
@@ -195,7 +200,7 @@ func discv4ResolveJSON(ctx *cli.Context) error {
|
||||
defer disc.Close()
|
||||
c := newCrawler(inputSet, disc, enode.IterNodes(nodeargs))
|
||||
c.revalidateInterval = 0
|
||||
output := c.run(0)
|
||||
output := c.run(0, 1)
|
||||
writeNodesJSON(nodesFile, output)
|
||||
return nil
|
||||
}
|
||||
@@ -214,7 +219,7 @@ func discv4Crawl(ctx *cli.Context) error {
|
||||
defer disc.Close()
|
||||
c := newCrawler(inputSet, disc, disc.RandomNodes())
|
||||
c.revalidateInterval = 10 * time.Minute
|
||||
output := c.run(ctx.Duration(crawlTimeoutFlag.Name))
|
||||
output := c.run(ctx.Duration(crawlTimeoutFlag.Name), ctx.Int(crawlParallelismFlag.Name))
|
||||
writeNodesJSON(nodesFile, output)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ func discv5Crawl(ctx *cli.Context) error {
|
||||
defer disc.Close()
|
||||
c := newCrawler(inputSet, disc, disc.RandomNodes())
|
||||
c.revalidateInterval = 10 * time.Minute
|
||||
output := c.run(ctx.Duration(crawlTimeoutFlag.Name))
|
||||
output := c.run(ctx.Duration(crawlTimeoutFlag.Name), ctx.Int(crawlParallelismFlag.Name))
|
||||
writeNodesJSON(nodesFile, output)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -126,11 +126,16 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string)
|
||||
}
|
||||
|
||||
// Iterate over the new records and inject anything missing.
|
||||
log.Info("Updating DNS entries")
|
||||
created := 0
|
||||
updated := 0
|
||||
skipped := 0
|
||||
for path, val := range records {
|
||||
old, exists := existing[path]
|
||||
if !exists {
|
||||
// Entry is unknown, push a new one to Cloudflare.
|
||||
log.Info(fmt.Sprintf("Creating %s = %q", path, val))
|
||||
log.Debug(fmt.Sprintf("Creating %s = %q", path, val))
|
||||
created++
|
||||
ttl := rootTTL
|
||||
if path != name {
|
||||
ttl = treeNodeTTLCloudflare // Max TTL permitted by Cloudflare
|
||||
@@ -139,27 +144,33 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string)
|
||||
_, err = c.CreateDNSRecord(context.Background(), c.zoneID, record)
|
||||
} else if old.Content != val {
|
||||
// Entry already exists, only change its content.
|
||||
log.Info(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val))
|
||||
log.Debug(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val))
|
||||
updated++
|
||||
old.Content = val
|
||||
err = c.UpdateDNSRecord(context.Background(), c.zoneID, old.ID, old)
|
||||
} else {
|
||||
skipped++
|
||||
log.Debug(fmt.Sprintf("Skipping %s = %q", path, val))
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to publish %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Updated DNS entries", "new", created, "updated", updated, "untouched", skipped)
|
||||
// Iterate over the old records and delete anything stale.
|
||||
deleted := 0
|
||||
log.Info("Deleting stale DNS entries")
|
||||
for path, entry := range existing {
|
||||
if _, ok := records[path]; ok {
|
||||
continue
|
||||
}
|
||||
// Stale entry, nuke it.
|
||||
log.Info(fmt.Sprintf("Deleting %s = %q", path, entry.Content))
|
||||
log.Debug(fmt.Sprintf("Deleting %s = %q", path, entry.Content))
|
||||
deleted++
|
||||
if err := c.DeleteDNSRecord(context.Background(), c.zoneID, entry.ID); err != nil {
|
||||
return fmt.Errorf("failed to delete %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
log.Info("Deleted stale DNS entries", "count", deleted)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -329,8 +329,9 @@ func (c *route53Client) collectRecords(name string) (map[string]recordSet, error
|
||||
var req route53.ListResourceRecordSetsInput
|
||||
req.HostedZoneId = &c.zoneID
|
||||
existing := make(map[string]recordSet)
|
||||
log.Info("Loading existing TXT records", "name", name, "zone", c.zoneID)
|
||||
for page := 0; ; page++ {
|
||||
log.Info("Loading existing TXT records", "name", name, "zone", c.zoneID, "page", page)
|
||||
log.Debug("Loading existing TXT records", "name", name, "zone", c.zoneID, "page", page)
|
||||
resp, err := c.api.ListResourceRecordSets(context.TODO(), &req)
|
||||
if err != nil {
|
||||
return existing, err
|
||||
@@ -360,7 +361,7 @@ func (c *route53Client) collectRecords(name string) (map[string]recordSet, error
|
||||
req.StartRecordName = resp.NextRecordName
|
||||
req.StartRecordType = resp.NextRecordType
|
||||
}
|
||||
|
||||
log.Info("Loaded existing TXT records", "name", name, "zone", c.zoneID, "records", len(existing))
|
||||
return existing, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
||||
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||
@@ -210,13 +211,6 @@ type byteCodesTest struct {
|
||||
expHashes int
|
||||
}
|
||||
|
||||
var (
|
||||
// emptyRoot is the known root hash of an empty trie.
|
||||
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
// emptyCode is the known hash of the empty EVM bytecode.
|
||||
emptyCode = common.HexToHash("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
|
||||
)
|
||||
|
||||
// TestSnapGetByteCodes various forms of GetByteCodes requests.
|
||||
func (s *Suite) TestSnapGetByteCodes(t *utesting.T) {
|
||||
// The halfchain import should yield these bytecodes
|
||||
@@ -263,15 +257,15 @@ func (s *Suite) TestSnapGetByteCodes(t *utesting.T) {
|
||||
},
|
||||
// Empties
|
||||
{
|
||||
nBytes: 10000, hashes: []common.Hash{emptyRoot},
|
||||
nBytes: 10000, hashes: []common.Hash{types.EmptyRootHash},
|
||||
expHashes: 0,
|
||||
},
|
||||
{
|
||||
nBytes: 10000, hashes: []common.Hash{emptyCode},
|
||||
nBytes: 10000, hashes: []common.Hash{types.EmptyCodeHash},
|
||||
expHashes: 1,
|
||||
},
|
||||
{
|
||||
nBytes: 10000, hashes: []common.Hash{emptyCode, emptyCode, emptyCode},
|
||||
nBytes: 10000, hashes: []common.Hash{types.EmptyCodeHash, types.EmptyCodeHash, types.EmptyCodeHash},
|
||||
expHashes: 3,
|
||||
},
|
||||
// The existing bytecodes
|
||||
@@ -363,7 +357,7 @@ func (s *Suite) TestSnapTrieNodes(t *utesting.T) {
|
||||
for i := 1; i <= 65; i++ {
|
||||
accPaths = append(accPaths, pathTo(i))
|
||||
}
|
||||
empty := emptyCode
|
||||
empty := types.EmptyCodeHash
|
||||
for i, tc := range []trieNodesTest{
|
||||
{
|
||||
root: s.chain.RootAt(999),
|
||||
|
||||
@@ -120,8 +120,8 @@ func (i *bbInput) ToBlock() *types.Block {
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
Coinbase: common.Address{},
|
||||
Root: i.Header.Root,
|
||||
TxHash: types.EmptyRootHash,
|
||||
ReceiptHash: types.EmptyRootHash,
|
||||
TxHash: types.EmptyTxsHash,
|
||||
ReceiptHash: types.EmptyReceiptsHash,
|
||||
Bloom: i.Header.Bloom,
|
||||
Difficulty: common.Big0,
|
||||
Number: i.Header.Number,
|
||||
|
||||
@@ -163,7 +163,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
}
|
||||
|
||||
for i, tx := range txs {
|
||||
msg, err := tx.AsMessage(signer, pre.Env.BaseFee)
|
||||
msg, err := core.TransactionToMessage(tx, signer, pre.Env.BaseFee)
|
||||
if err != nil {
|
||||
log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err)
|
||||
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
||||
@@ -176,16 +176,21 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
vmConfig.Tracer = tracer
|
||||
vmConfig.Debug = (tracer != nil)
|
||||
statedb.SetTxContext(tx.Hash(), txIndex)
|
||||
txContext := core.NewEVMTxContext(msg)
|
||||
snapshot := statedb.Snapshot()
|
||||
|
||||
var (
|
||||
txContext = core.NewEVMTxContext(msg)
|
||||
snapshot = statedb.Snapshot()
|
||||
prevGas = gaspool.Gas()
|
||||
)
|
||||
evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
|
||||
|
||||
// (ret []byte, usedGas uint64, failed bool, err error)
|
||||
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
|
||||
if err != nil {
|
||||
statedb.RevertToSnapshot(snapshot)
|
||||
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err)
|
||||
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
|
||||
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
||||
gaspool.SetGas(prevGas)
|
||||
continue
|
||||
}
|
||||
includedTxs = append(includedTxs, tx)
|
||||
@@ -215,7 +220,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
receipt.GasUsed = msgResult.UsedGas
|
||||
|
||||
// If the transaction created a contract, store the creation address in the receipt.
|
||||
if msg.To() == nil {
|
||||
if msg.To == nil {
|
||||
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
||||
}
|
||||
|
||||
|
||||
134
cmd/evm/testdata/10/readme.md
vendored
134
cmd/evm/testdata/10/readme.md
vendored
@@ -9,71 +9,77 @@ INFO [05-09|22:11:59.436] rejected tx index=3 hash=
|
||||
Output:
|
||||
```json
|
||||
{
|
||||
"alloc": {
|
||||
"0x1111111111111111111111111111111111111111": {
|
||||
"code": "0xfe",
|
||||
"balance": "0x10000000000",
|
||||
"nonce": "0x1"
|
||||
"alloc": {
|
||||
"0x1111111111111111111111111111111111111111": {
|
||||
"code": "0xfe",
|
||||
"balance": "0x10000000000",
|
||||
"nonce": "0x1"
|
||||
},
|
||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0x10000000000",
|
||||
"nonce": "0x1"
|
||||
},
|
||||
"0xd02d72e067e77158444ef2020ff2d325f929b363": {
|
||||
"balance": "0xff5beffffc95",
|
||||
"nonce": "0x4"
|
||||
}
|
||||
},
|
||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0x10000000000",
|
||||
"nonce": "0x1"
|
||||
},
|
||||
"0xd02d72e067e77158444ef2020ff2d325f929b363": {
|
||||
"balance": "0xff5beffffc95",
|
||||
"nonce": "0x4"
|
||||
"result": {
|
||||
"stateRoot": "0xf91a7ec08e4bfea88719aab34deabb000c86902360532b52afa9599d41f2bb8b",
|
||||
"txRoot": "0xda925f2306a52fa24c15d5cd212d736ee016415fd8dd0c45fd368de7917d64bb",
|
||||
"receiptsRoot": "0x439a25f7fc424c10fb1f89800e4aa1df74156b137239d9ac3eaa7c911c353cd5",
|
||||
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"receipts": [
|
||||
{
|
||||
"type": "0x2",
|
||||
"root": "0x",
|
||||
"status": "0x0",
|
||||
"cumulativeGasUsed": "0x10000001",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"logs": null,
|
||||
"transactionHash": "0x88980f6efcc5358d9c359663e7b9414722d430497637340ea056b076bc206701",
|
||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||
"gasUsed": "0x10000001",
|
||||
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"transactionIndex": "0x0"
|
||||
},
|
||||
{
|
||||
"type": "0x2",
|
||||
"root": "0x",
|
||||
"status": "0x0",
|
||||
"cumulativeGasUsed": "0x20000001",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"logs": null,
|
||||
"transactionHash": "0xd7bf3886f4e2aef74d525ae072c680f3846f550254401b67cbfda4a233757582",
|
||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||
"gasUsed": "0x10000000",
|
||||
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"transactionIndex": "0x1"
|
||||
},
|
||||
{
|
||||
"type": "0x2",
|
||||
"root": "0x",
|
||||
"status": "0x0",
|
||||
"cumulativeGasUsed": "0x30000001",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"logs": null,
|
||||
"transactionHash": "0x50308296760f01f1eeec7500e9e73cad67469249b1f59e9a9f55e6625a4923db",
|
||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||
"gasUsed": "0x10000000",
|
||||
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"transactionIndex": "0x2"
|
||||
}
|
||||
],
|
||||
"rejected": [
|
||||
{
|
||||
"index": 3,
|
||||
"error": "gas limit reached"
|
||||
}
|
||||
],
|
||||
"currentDifficulty": "0x20000",
|
||||
"gasUsed": "0x30000001",
|
||||
"currentBaseFee": "0x36b"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"stateRoot": "0xf91a7ec08e4bfea88719aab34deabb000c86902360532b52afa9599d41f2bb8b",
|
||||
"txRoot": "0xda925f2306a52fa24c15d5cd212d736ee016415fd8dd0c45fd368de7917d64bb",
|
||||
"receiptRoot": "0x439a25f7fc424c10fb1f89800e4aa1df74156b137239d9ac3eaa7c911c353cd5",
|
||||
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"receipts": [
|
||||
{
|
||||
"type": "0x2",
|
||||
"root": "0x",
|
||||
"status": "0x0",
|
||||
"cumulativeGasUsed": "0x10000001",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"logs": null,
|
||||
"transactionHash": "0x88980f6efcc5358d9c359663e7b9414722d430497637340ea056b076bc206701",
|
||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||
"gasUsed": "0x10000001",
|
||||
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"transactionIndex": "0x0"
|
||||
},
|
||||
{
|
||||
"type": "0x2",
|
||||
"root": "0x",
|
||||
"status": "0x0",
|
||||
"cumulativeGasUsed": "0x20000001",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"logs": null,
|
||||
"transactionHash": "0xd7bf3886f4e2aef74d525ae072c680f3846f550254401b67cbfda4a233757582",
|
||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||
"gasUsed": "0x10000000",
|
||||
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"transactionIndex": "0x1"
|
||||
},
|
||||
{
|
||||
"type": "0x2",
|
||||
"root": "0x",
|
||||
"status": "0x0",
|
||||
"cumulativeGasUsed": "0x30000001",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"logs": null,
|
||||
"transactionHash": "0x50308296760f01f1eeec7500e9e73cad67469249b1f59e9a9f55e6625a4923db",
|
||||
"contractAddress": "0x0000000000000000000000000000000000000000",
|
||||
"gasUsed": "0x10000000",
|
||||
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"transactionIndex": "0x2"
|
||||
}
|
||||
],
|
||||
"rejected": [
|
||||
3
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
45
cmd/evm/testdata/12/readme.md
vendored
45
cmd/evm/testdata/12/readme.md
vendored
@@ -11,29 +11,32 @@ dir=./testdata/12 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json
|
||||
With the fix applied, the result is:
|
||||
```
|
||||
dir=./testdata/12 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout --output.result=stdout
|
||||
INFO [07-21|19:03:50.276] rejected tx index=0 hash=ccc996..d83435 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="insufficient funds for gas * price + value: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B have 84000000 want 84000032"
|
||||
INFO [07-21|19:03:50.276] Trie dumping started root=e05f81..6597a5
|
||||
INFO [07-21|19:03:50.276] Trie dumping complete accounts=1 elapsed="39.549µs"
|
||||
INFO [03-09|10:43:12.649] rejected tx index=0 hash=ccc996..d83435 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="insufficient funds for gas * price + value: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B have 84000000 want 84000032"
|
||||
INFO [03-09|10:43:12.650] Trie dumping started root=e05f81..6597a5
|
||||
INFO [03-09|10:43:12.650] Trie dumping complete accounts=1 elapsed="46.393µs"
|
||||
{
|
||||
"alloc": {
|
||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0x501bd00"
|
||||
"alloc": {
|
||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0x501bd00"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"stateRoot": "0xe05f81f8244a76503ceec6f88abfcd03047a612a1001217f37d30984536597a5",
|
||||
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"receipts": [],
|
||||
"rejected": [
|
||||
{
|
||||
"index": 0,
|
||||
"error": "insufficient funds for gas * price + value: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B have 84000000 want 84000032"
|
||||
}
|
||||
],
|
||||
"currentDifficulty": "0x20000",
|
||||
"gasUsed": "0x0",
|
||||
"currentBaseFee": "0x20"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"stateRoot": "0xe05f81f8244a76503ceec6f88abfcd03047a612a1001217f37d30984536597a5",
|
||||
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"receiptRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"receipts": [],
|
||||
"rejected": [
|
||||
{
|
||||
"index": 0,
|
||||
"error": "insufficient funds for gas * price + value: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B have 84000000 want 84000032"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
24
cmd/evm/testdata/14/readme.md
vendored
24
cmd/evm/testdata/14/readme.md
vendored
@@ -5,36 +5,40 @@ This test shows how the `evm t8n` can be used to calculate the (ethash) difficul
|
||||
Calculating it (with an empty set of txs) using `London` rules (and no provided unclehash for the parent block):
|
||||
```
|
||||
[user@work evm]$ ./evm t8n --input.alloc=./testdata/14/alloc.json --input.txs=./testdata/14/txs.json --input.env=./testdata/14/env.json --output.result=stdout --state.fork=London
|
||||
INFO [08-30|20:43:09.352] Trie dumping started root=6f0588..7f4bdc
|
||||
INFO [08-30|20:43:09.352] Trie dumping complete accounts=2 elapsed="82.533µs"
|
||||
INFO [08-30|20:43:09.352] Wrote file file=alloc.json
|
||||
INFO [03-09|10:43:57.070] Trie dumping started root=6f0588..7f4bdc
|
||||
INFO [03-09|10:43:57.070] Trie dumping complete accounts=2 elapsed="214.663µs"
|
||||
INFO [03-09|10:43:57.071] Wrote file file=alloc.json
|
||||
{
|
||||
"result": {
|
||||
"stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc",
|
||||
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"receiptRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"receipts": [],
|
||||
"currentDifficulty": "0x2000020000000"
|
||||
"currentDifficulty": "0x2000020000000",
|
||||
"gasUsed": "0x0",
|
||||
"currentBaseFee": "0x500"
|
||||
}
|
||||
}
|
||||
```
|
||||
Same thing, but this time providing a non-empty (and non-`emptyKeccak`) unclehash, which leads to a slightly different result:
|
||||
```
|
||||
[user@work evm]$ ./evm t8n --input.alloc=./testdata/14/alloc.json --input.txs=./testdata/14/txs.json --input.env=./testdata/14/env.uncles.json --output.result=stdout --state.fork=London
|
||||
INFO [08-30|20:44:33.102] Trie dumping started root=6f0588..7f4bdc
|
||||
INFO [08-30|20:44:33.102] Trie dumping complete accounts=2 elapsed="72.91µs"
|
||||
INFO [08-30|20:44:33.102] Wrote file file=alloc.json
|
||||
INFO [03-09|10:44:20.511] Trie dumping started root=6f0588..7f4bdc
|
||||
INFO [03-09|10:44:20.511] Trie dumping complete accounts=2 elapsed="184.319µs"
|
||||
INFO [03-09|10:44:20.512] Wrote file file=alloc.json
|
||||
{
|
||||
"result": {
|
||||
"stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc",
|
||||
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"receiptRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"receipts": [],
|
||||
"currentDifficulty": "0x1ff8020000000"
|
||||
"currentDifficulty": "0x1ff8020000000",
|
||||
"gasUsed": "0x0",
|
||||
"currentBaseFee": "0x500"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
16
cmd/evm/testdata/19/readme.md
vendored
16
cmd/evm/testdata/19/readme.md
vendored
@@ -6,4 +6,20 @@ this time on `GrayGlacier` (Eip 5133).
|
||||
Calculating it (with an empty set of txs) using `GrayGlacier` rules (and no provided unclehash for the parent block):
|
||||
```
|
||||
[user@work evm]$ ./evm t8n --input.alloc=./testdata/19/alloc.json --input.txs=./testdata/19/txs.json --input.env=./testdata/19/env.json --output.result=stdout --state.fork=GrayGlacier
|
||||
INFO [03-09|10:45:26.777] Trie dumping started root=6f0588..7f4bdc
|
||||
INFO [03-09|10:45:26.777] Trie dumping complete accounts=2 elapsed="176.471µs"
|
||||
INFO [03-09|10:45:26.777] Wrote file file=alloc.json
|
||||
{
|
||||
"result": {
|
||||
"stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc",
|
||||
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"receipts": [],
|
||||
"currentDifficulty": "0x2000000004000",
|
||||
"gasUsed": "0x0",
|
||||
"currentBaseFee": "0x500"
|
||||
}
|
||||
}
|
||||
```
|
||||
370
cmd/evm/testdata/7/readme.md
vendored
370
cmd/evm/testdata/7/readme.md
vendored
@@ -3,5 +3,373 @@ DAO-transition works
|
||||
|
||||
Example:
|
||||
```
|
||||
./statet8n --input.alloc=./testdata/7/alloc.json --input.txs=./testdata/7/txs.json --input.env=./testdata/7/env.json --output.alloc=stdout --state.fork=HomesteadToDaoAt5
|
||||
./evm t8n --input.alloc=./testdata/7/alloc.json --input.txs=./testdata/7/txs.json --input.env=./testdata/7/env.json --output.alloc=stdout --state.fork=HomesteadToDaoAt5
|
||||
INFO [03-09|10:47:37.255] Trie dumping started root=157847..2891b7
|
||||
INFO [03-09|10:47:37.256] Trie dumping complete accounts=120 elapsed="715.635µs"
|
||||
INFO [03-09|10:47:37.256] Wrote file file=result.json
|
||||
{
|
||||
"alloc": {
|
||||
"0x005f5cee7a43331d5a3d3eec71305925a62f34b6": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x057b56736d32b86616a10f619859c6cd6f59092a": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x0737a6b837f97f46ebade41b9bc3e1c509c85c53": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x12e626b0eebfe86a56d633b9864e389b45dcb260": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x1591fc0f688c81fbeb17f5426a162a7024d430c2": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x17802f43a0137c506ba92291391a8a8f207f487d": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x1975bd06d486162d5dc297798dfc41edd5d160a7": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x1cba23d343a983e9b5cfd19496b9a9701ada385f": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x200450f06520bdd6c527622a273333384d870efb": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x23b75c2f6791eef49c69684db4c6c1f93bf49a50": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x24c4d950dfd4dd1902bbed3508144a54542bba94": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x253488078a4edf4d6f42f113d1e62836a942cf1a": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x27b137a85656544b1ccb5a0f2e561a5703c6a68f": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x2a5ed960395e2a49b1c758cef4aa15213cfd874c": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x304a554a310c7e546dfe434669c62820b7d83490": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x319f70bab6845585f412ec7724b744fec6095c85": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x3ba4d81db016dc2890c81f3acec2454bff5aada5": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x40b803a9abce16f50f36a77ba41180eb90023925": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x440c59b325d2997a134c2c7c60a8c61611212bad": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x4486a3d68fac6967006d7a517b889fd3f98c102b": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x47e7aa56d6bdf3f36be34619660de61275420af8": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x4863226780fe7c0356454236d3b1c8792785748d": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x492ea3bb0f3315521c31f273e565b868fc090f17": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x4deb0033bb26bc534b197e61d19e0733e5679784": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x4fa802324e929786dbda3b8820dc7834e9134a2a": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x4fd6ace747f06ece9c49699c7cabc62d02211f75": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x51e0ddd9998364a2eb38588679f0d2c42653e4a6": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x52c5317c848ba20c7504cb2c8052abd1fde29d03": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x542a9515200d14b68e934e9830d91645a980dd7a": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x5524c55fb03cf21f549444ccbecb664d0acad706": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x579a80d909f346fbfb1189493f521d7f48d52238": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x5c8536898fbb74fc7445814902fd08422eac56d0": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x5d2b2e6fcbe3b11d26b525e085ff818dae332479": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x5dc28b15dffed94048d73806ce4b7a4612a1d48f": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x6131c42fa982e56929107413a9d526fd99405560": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x6231b6d0d5e77fe001c2a460bd9584fee60d409b": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x627a0a960c079c21c34f7612d5d230e01b4ad4c7": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x63ed5a272de2f6d968408b4acb9024f4cc208ebf": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x6966ab0d485353095148a2155858910e0965b6f9": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x6d87578288b6cb5549d5076a207456a1f6a63dc0": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x6f6704e5a10332af6672e50b3d9754dc460dfa4d": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x779543a0491a837ca36ce8c635d6154e3c4911a6": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": {
|
||||
"balance": "0xfeedbead"
|
||||
},
|
||||
"0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x97f43a37f595ab5dd318fb46e7a155eae057317a": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x9aa008f65de0b923a2a4f02012ad034a5e2e2192": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x9c15b54878ba618f494b38f0ae7443db6af648ba": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x9c50426be05db97f5d64fc54bf89eff947f0a321": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x9da397b9e80755301a3b32173283a91c0ef6c87e": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x9ea779f907f0b315b364b0cfc39a0fde5b02a416": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x9f27daea7aca0aa0446220b98d028715e3bc803d": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xa82f360a8d3455c5c41366975bde739c37bfeb8a": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0x5ffd4878be161d74",
|
||||
"nonce": "0xac"
|
||||
},
|
||||
"0xac1ecab32727358dba8962a0f3b261731aad9723": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xacd87e28b0c9d1254e868b81cba4cc20d9a32225": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xadf80daec7ba8dcf15392f1ac611fff65d94f880": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xb136707642a4ea12fb4bae820f03d2562ebff487": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xb9637156d330c0d605a791f1c31ba5890582fe1c": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xbc07118b9ac290e4622f5e77a0853539789effbe": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xbe8539bfe837b67d1282b2b1d61c3f723966f049": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xbf4ed7b27f1d666546e30d74d50d173d20bca754": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xc4bbd073882dd2add2424cf47d35213405b01324": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xca544e5c4687d109611d0f8f928b53a25af72448": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xcc34673c6c40e791051898567a1222daf90be287": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xceaeb481747ca6c540a000c1f3641f8cef161fa7": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xd131637d5275fd1a68a3200f4ad25c71a2a9522e": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xd164b088bd9108b60d0ca3751da4bceb207b0782": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xd343b217de44030afaa275f54d31a9317c7f441e": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xda2fef9e4a3230988ff17df2165440f37e8b1708": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xe308bd1ac5fda103967359b2712dd89deffb7973": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xe4ae1efdfc53b73893af49113d8694a057b9c0d1": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xecd135fa4f61a655311e86238c92adcd779555d2": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xf0b1aa0eb660754448a7937c022e30aa692fe0c5": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xf1385fb24aad0cd7432824085e42aff90886fef5": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xf14c14075d6c4ed84b86798af0956deef67365b5": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xf4c64518ea10f995918a454158c6b61407ea345c": {
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f": {
|
||||
"balance": "0x0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
38
cmd/evm/testdata/8/readme.md
vendored
38
cmd/evm/testdata/8/readme.md
vendored
@@ -23,41 +23,37 @@ There are three transactions, each invokes the contract above.
|
||||
|
||||
Running it yields:
|
||||
```
|
||||
dir=./testdata/8 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace && cat trace-* | grep SLOAD
|
||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
|
||||
dir=./testdata/8 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace 2>/dev/null && cat trace-* | grep SLOAD
|
||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
```
|
||||
|
||||
Simlarly, we can provide the input transactions via `stdin` instead of as file:
|
||||
|
||||
```
|
||||
dir=./testdata/8 \
|
||||
$ dir=./testdata/8 \
|
||||
&& cat $dir/txs.json | jq "{txs: .}" \
|
||||
| ./evm t8n --state.fork=Berlin \
|
||||
--input.alloc=$dir/alloc.json \
|
||||
--input.txs=stdin \
|
||||
--input.env=$dir/env.json \
|
||||
--trace \
|
||||
2>/dev/null \
|
||||
&& cat trace-* | grep SLOAD
|
||||
|
||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
```
|
||||
|
||||
If we try to execute it on older rules:
|
||||
```
|
||||
dir=./testdata/8 && ./evm t8n --state.fork=Istanbul --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json
|
||||
INFO [01-21|23:21:51.265] rejected tx index=0 hash=d2818d..6ab3da error="tx type not supported"
|
||||
INFO [01-21|23:21:51.265] rejected tx index=1 hash=26ea00..81c01b from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="nonce too high: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B, tx: 1 state: 0"
|
||||
INFO [01-21|23:21:51.265] rejected tx index=2 hash=698d01..369cee error="tx type not supported"
|
||||
$ dir=./testdata/8 && ./evm t8n --state.fork=Istanbul --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json
|
||||
ERROR(10): failed signing transactions: ERROR(10): tx 0: failed to sign tx: transaction type not supported
|
||||
```
|
||||
Number `1` and `3` are not applicable, and therefore number `2` has wrong nonce.
|
||||
2
cmd/evm/testdata/9/env.json
vendored
2
cmd/evm/testdata/9/env.json
vendored
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentDifficulty": "0x20000",
|
||||
"currentGasTarget": "0x1000000000",
|
||||
"currentGasLimit": "0x1000000000",
|
||||
"currentBaseFee": "0x3B9ACA00",
|
||||
"currentNumber": "0x1000000",
|
||||
"currentTimestamp": "0x04"
|
||||
|
||||
58
cmd/evm/testdata/9/readme.md
vendored
58
cmd/evm/testdata/9/readme.md
vendored
@@ -22,35 +22,37 @@ There are two transactions, each invokes the contract above.
|
||||
|
||||
Running it yields:
|
||||
```
|
||||
$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace && cat trace-* | grep SLOAD
|
||||
{"pc":2,"op":84,"gas":"0x48c28","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x1"],"returnStack":null,"returnD
|
||||
ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":3,"op":84,"gas":"0x483f4","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0","0x0"],"returnStack":null,"returnDa
|
||||
ta":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":2,"op":84,"gas":"0x49cf4","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x1"],"returnStack":null,"returnD
|
||||
ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
{"pc":3,"op":84,"gas":"0x494c0","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x0"],"returnStack":null,"returnD
|
||||
ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
||||
$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace 2>/dev/null && cat trace-* | grep SLOAD
|
||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":2,"op":84,"gas":"0x48c28","gasCost":"0x834","memSize":0,"stack":["0x0","0x1"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":3,"op":84,"gas":"0x483f4","gasCost":"0x64","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":2,"op":84,"gas":"0x49cf4","gasCost":"0x834","memSize":0,"stack":["0x0","0x1"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":3,"op":84,"gas":"0x494c0","gasCost":"0x834","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||
```
|
||||
|
||||
We can also get the post-alloc:
|
||||
```
|
||||
$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout
|
||||
$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout 2>/dev/null
|
||||
{
|
||||
"alloc": {
|
||||
"0x000000000000000000000000000000000000aaaa": {
|
||||
"code": "0x58585454",
|
||||
"balance": "0x3",
|
||||
"nonce": "0x1"
|
||||
},
|
||||
"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": {
|
||||
"balance": "0xbfc02677a000"
|
||||
},
|
||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0xff104fcfea7800",
|
||||
"nonce": "0x2"
|
||||
"alloc": {
|
||||
"0x000000000000000000000000000000000000aaaa": {
|
||||
"code": "0x58585454",
|
||||
"balance": "0x3",
|
||||
"nonce": "0x1"
|
||||
},
|
||||
"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": {
|
||||
"balance": "0x5bb10ddef6e0"
|
||||
},
|
||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0xff745ee8832120",
|
||||
"nonce": "0x2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -65,10 +67,12 @@ by feeding it presigned transactions, located in `txs_signed.json`.
|
||||
|
||||
```
|
||||
dir=./testdata/9 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs_signed.json --input.env=$dir/env.json
|
||||
INFO [05-07|12:28:42.072] rejected tx index=0 hash=b4821e..536819 error="transaction type not supported"
|
||||
INFO [05-07|12:28:42.072] rejected tx index=1 hash=a9c6c6..fa4036 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="nonce too high: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B, tx: 1 state: 0"
|
||||
INFO [05-07|12:28:42.073] Wrote file file=alloc.json
|
||||
INFO [05-07|12:28:42.073] Wrote file file=result.json
|
||||
WARN [03-09|11:06:22.065] rejected tx index=0 hash=334e09..f8dce5 error="transaction type not supported"
|
||||
INFO [03-09|11:06:22.066] rejected tx index=1 hash=a9c6c6..fa4036 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="nonce too high: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B, tx: 1 state: 0"
|
||||
INFO [03-09|11:06:22.066] Trie dumping started root=6eebe9..a0fda5
|
||||
INFO [03-09|11:06:22.066] Trie dumping complete accounts=2 elapsed="55.844µs"
|
||||
INFO [03-09|11:06:22.066] Wrote file file=alloc.json
|
||||
INFO [03-09|11:06:22.066] Wrote file file=result.json
|
||||
```
|
||||
|
||||
Number `0` is not applicable, and therefore number `1` has wrong nonce, and both are rejected.
|
||||
|
||||
37
cmd/evm/testdata/9/txs_signed.json
vendored
Normal file
37
cmd/evm/testdata/9/txs_signed.json
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
[
|
||||
{
|
||||
"gas": "0x4ef00",
|
||||
"maxFeePerGas": "0x2",
|
||||
"maxPriorityFeePerGas": "0x12A05F200",
|
||||
"chainId": "0x1",
|
||||
"input": "0x",
|
||||
"nonce": "0x0",
|
||||
"to": "0x000000000000000000000000000000000000aaaa",
|
||||
"value": "0x0",
|
||||
"type" : "0x2",
|
||||
"accessList": [
|
||||
{"address": "0x000000000000000000000000000000000000aaaa",
|
||||
"storageKeys": [
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
]
|
||||
}
|
||||
],
|
||||
"v": "0x1",
|
||||
"r": "0xd77c8ff989789b5d9d99254cbae2e2996dc7e6215cba4d55254c14e6d6b9f314",
|
||||
"s": "0x5cc021481e7e6bb444bbb87ab32071e8fd0a8d1e125c7bb352d2879bd7ff5c0a",
|
||||
"secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
|
||||
},
|
||||
{
|
||||
"gas": "0x4ef00",
|
||||
"gasPrice": "0x12A05F200",
|
||||
"chainId": "0x1",
|
||||
"input": "0x",
|
||||
"nonce": "0x1",
|
||||
"to": "0x000000000000000000000000000000000000aaaa",
|
||||
"value": "0x0",
|
||||
"v": "0x25",
|
||||
"r": "0xbee5ec9f6650020266bf3455a852eece2b073a2fa918c4d1836a1af69c2aa50c",
|
||||
"s": "0x556c897a58dbc007a6b09814e1fba7502adb76effd2146da4365816926f387ce",
|
||||
"secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
|
||||
}
|
||||
]
|
||||
@@ -349,8 +349,8 @@ func exportChain(ctx *cli.Context) error {
|
||||
if first < 0 || last < 0 {
|
||||
utils.Fatalf("Export error: block number must be greater than 0\n")
|
||||
}
|
||||
if head := chain.CurrentFastBlock(); uint64(last) > head.NumberU64() {
|
||||
utils.Fatalf("Export error: block number %d larger than head block %d\n", uint64(last), head.NumberU64())
|
||||
if head := chain.CurrentSnapBlock(); uint64(last) > head.Number.Uint64() {
|
||||
utils.Fatalf("Export error: block number %d larger than head block %d\n", uint64(last), head.Number.Uint64())
|
||||
}
|
||||
err = utils.ExportAppendChain(chain, fp, uint64(first), uint64(last))
|
||||
}
|
||||
|
||||
@@ -47,10 +47,10 @@ var (
|
||||
dumpConfigCommand = &cli.Command{
|
||||
Action: dumpConfig,
|
||||
Name: "dumpconfig",
|
||||
Usage: "Show configuration values",
|
||||
ArgsUsage: "",
|
||||
Usage: "Export configuration values in a TOML format",
|
||||
ArgsUsage: "<dumpfile (optional)>",
|
||||
Flags: flags.Merge(nodeFlags, rpcFlags),
|
||||
Description: `The dumpconfig command shows configuration values.`,
|
||||
Description: `Export configuration values in TOML format (to stdout by default).`,
|
||||
}
|
||||
|
||||
configFileFlag = &cli.StringFlag{
|
||||
|
||||
@@ -694,41 +694,19 @@ func showMetaData(ctx *cli.Context) error {
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error accessing ancients: %v", err)
|
||||
}
|
||||
pp := func(val *uint64) string {
|
||||
if val == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return fmt.Sprintf("%d (%#x)", *val, *val)
|
||||
}
|
||||
data := [][]string{
|
||||
{"databaseVersion", pp(rawdb.ReadDatabaseVersion(db))},
|
||||
{"headBlockHash", fmt.Sprintf("%v", rawdb.ReadHeadBlockHash(db))},
|
||||
{"headFastBlockHash", fmt.Sprintf("%v", rawdb.ReadHeadFastBlockHash(db))},
|
||||
{"headHeaderHash", fmt.Sprintf("%v", rawdb.ReadHeadHeaderHash(db))}}
|
||||
data := rawdb.ReadChainMetadata(db)
|
||||
data = append(data, []string{"frozen", fmt.Sprintf("%d items", ancients)})
|
||||
data = append(data, []string{"snapshotGenerator", snapshot.ParseGeneratorStatus(rawdb.ReadSnapshotGenerator(db))})
|
||||
if b := rawdb.ReadHeadBlock(db); b != nil {
|
||||
data = append(data, []string{"headBlock.Hash", fmt.Sprintf("%v", b.Hash())})
|
||||
data = append(data, []string{"headBlock.Root", fmt.Sprintf("%v", b.Root())})
|
||||
data = append(data, []string{"headBlock.Number", fmt.Sprintf("%d (%#x)", b.Number(), b.Number())})
|
||||
}
|
||||
if b := rawdb.ReadSkeletonSyncStatus(db); b != nil {
|
||||
data = append(data, []string{"SkeletonSyncStatus", string(b)})
|
||||
}
|
||||
if h := rawdb.ReadHeadHeader(db); h != nil {
|
||||
data = append(data, []string{"headHeader.Hash", fmt.Sprintf("%v", h.Hash())})
|
||||
data = append(data, []string{"headHeader.Root", fmt.Sprintf("%v", h.Root)})
|
||||
data = append(data, []string{"headHeader.Number", fmt.Sprintf("%d (%#x)", h.Number, h.Number)})
|
||||
}
|
||||
data = append(data, [][]string{{"frozen", fmt.Sprintf("%d items", ancients)},
|
||||
{"lastPivotNumber", pp(rawdb.ReadLastPivotNumber(db))},
|
||||
{"len(snapshotSyncStatus)", fmt.Sprintf("%d bytes", len(rawdb.ReadSnapshotSyncStatus(db)))},
|
||||
{"snapshotGenerator", snapshot.ParseGeneratorStatus(rawdb.ReadSnapshotGenerator(db))},
|
||||
{"snapshotDisabled", fmt.Sprintf("%v", rawdb.ReadSnapshotDisabled(db))},
|
||||
{"snapshotJournal", fmt.Sprintf("%d bytes", len(rawdb.ReadSnapshotJournal(db)))},
|
||||
{"snapshotRecoveryNumber", pp(rawdb.ReadSnapshotRecoveryNumber(db))},
|
||||
{"snapshotRoot", fmt.Sprintf("%v", rawdb.ReadSnapshotRoot(db))},
|
||||
{"txIndexTail", pp(rawdb.ReadTxIndexTail(db))},
|
||||
{"fastTxLookupLimit", pp(rawdb.ReadFastTxLookupLimit(db))},
|
||||
}...)
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"Field", "Value"})
|
||||
table.AppendBulk(data)
|
||||
|
||||
@@ -38,14 +38,6 @@ import (
|
||||
cli "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
// emptyRoot is the known root hash of an empty trie.
|
||||
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
|
||||
// emptyCode is the known hash of the empty EVM bytecode.
|
||||
emptyCode = crypto.Keccak256(nil)
|
||||
)
|
||||
|
||||
var (
|
||||
snapshotCommand = &cli.Command{
|
||||
Name: "snapshot",
|
||||
@@ -308,7 +300,7 @@ func traverseState(ctx *cli.Context) error {
|
||||
log.Error("Invalid account encountered during traversal", "err", err)
|
||||
return err
|
||||
}
|
||||
if acc.Root != emptyRoot {
|
||||
if acc.Root != types.EmptyRootHash {
|
||||
id := trie.StorageTrieID(root, common.BytesToHash(accIter.Key), acc.Root)
|
||||
storageTrie, err := trie.NewStateTrie(id, triedb)
|
||||
if err != nil {
|
||||
@@ -324,7 +316,7 @@ func traverseState(ctx *cli.Context) error {
|
||||
return storageIter.Err
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(acc.CodeHash, emptyCode) {
|
||||
if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) {
|
||||
if !rawdb.HasCode(chaindb, common.BytesToHash(acc.CodeHash)) {
|
||||
log.Error("Code is missing", "hash", common.BytesToHash(acc.CodeHash))
|
||||
return errors.New("missing code")
|
||||
@@ -423,7 +415,7 @@ func traverseRawState(ctx *cli.Context) error {
|
||||
log.Error("Invalid account encountered during traversal", "err", err)
|
||||
return errors.New("invalid account")
|
||||
}
|
||||
if acc.Root != emptyRoot {
|
||||
if acc.Root != types.EmptyRootHash {
|
||||
id := trie.StorageTrieID(root, common.BytesToHash(accIter.LeafKey()), acc.Root)
|
||||
storageTrie, err := trie.NewStateTrie(id, triedb)
|
||||
if err != nil {
|
||||
@@ -461,7 +453,7 @@ func traverseRawState(ctx *cli.Context) error {
|
||||
return storageIter.Error()
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(acc.CodeHash, emptyCode) {
|
||||
if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) {
|
||||
if !rawdb.HasCode(chaindb, common.BytesToHash(acc.CodeHash)) {
|
||||
log.Error("Code is missing", "account", common.BytesToHash(accIter.LeafKey()))
|
||||
return errors.New("missing code")
|
||||
@@ -536,7 +528,7 @@ func dumpState(ctx *cli.Context) error {
|
||||
CodeHash: account.CodeHash,
|
||||
SecureKey: accIt.Hash().Bytes(),
|
||||
}
|
||||
if !conf.SkipCode && !bytes.Equal(account.CodeHash, emptyCode) {
|
||||
if !conf.SkipCode && !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) {
|
||||
da.Code = rawdb.ReadCode(db, common.BytesToHash(account.CodeHash))
|
||||
}
|
||||
if !conf.SkipStorage {
|
||||
|
||||
@@ -222,7 +222,7 @@ func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block
|
||||
head := chain.CurrentBlock()
|
||||
for i, block := range blocks {
|
||||
// If we're behind the chain head, only check block, state is available at head
|
||||
if head.NumberU64() > block.NumberU64() {
|
||||
if head.Number.Uint64() > block.NumberU64() {
|
||||
if !chain.HasBlock(block.Hash(), block.NumberU64()) {
|
||||
return blocks[i:]
|
||||
}
|
||||
|
||||
@@ -49,6 +49,17 @@ func NewHexOrDecimal256(x int64) *HexOrDecimal256 {
|
||||
return &h
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
//
|
||||
// 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] == '"' {
|
||||
input = input[1 : len(input)-1]
|
||||
}
|
||||
return i.UnmarshalText(input)
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (i *HexOrDecimal256) UnmarshalText(input []byte) error {
|
||||
bigint, ok := ParseBig256(string(input))
|
||||
|
||||
@@ -41,6 +41,17 @@ const (
|
||||
// HexOrDecimal64 marshals uint64 as hex or decimal.
|
||||
type HexOrDecimal64 uint64
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
//
|
||||
// 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] == '"' {
|
||||
input = input[1 : len(input)-1]
|
||||
}
|
||||
return i.UnmarshalText(input)
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (i *HexOrDecimal64) UnmarshalText(input []byte) error {
|
||||
int, ok := ParseUint64(string(input))
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -93,7 +93,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||
if _, err := chain.InsertChain(blocks[:2]); err != nil {
|
||||
t.Fatalf("failed to insert initial blocks: %v", err)
|
||||
}
|
||||
if head := chain.CurrentBlock().NumberU64(); head != 2 {
|
||||
if head := chain.CurrentBlock().Number.Uint64(); head != 2 {
|
||||
t.Fatalf("chain head mismatch: have %d, want %d", head, 2)
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||
if _, err := chain.InsertChain(blocks[2:]); err != nil {
|
||||
t.Fatalf("failed to insert final block: %v", err)
|
||||
}
|
||||
if head := chain.CurrentBlock().NumberU64(); head != 3 {
|
||||
if head := chain.CurrentBlock().Number.Uint64(); head != 3 {
|
||||
t.Fatalf("chain head mismatch: have %d, want %d", head, 3)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,11 +709,11 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) {
|
||||
block := types.NewBlockWithHeader(&types.Header{
|
||||
Number: big.NewInt(3311058),
|
||||
ParentHash: common.HexToHash("0xd783efa4d392943503f28438ad5830b2d5964696ffc285f338585e9fe0a37a05"),
|
||||
UncleHash: common.HexToHash("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"),
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
Coinbase: common.HexToAddress("0xc0ea08a2d404d3172d2add29a45be56da40e2949"),
|
||||
Root: common.HexToHash("0x77d14e10470b5850332524f8cd6f69ad21f070ce92dca33ab2858300242ef2f1"),
|
||||
TxHash: common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"),
|
||||
ReceiptHash: common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"),
|
||||
TxHash: types.EmptyTxsHash,
|
||||
ReceiptHash: types.EmptyReceiptsHash,
|
||||
Difficulty: big.NewInt(167925187834220),
|
||||
GasLimit: 4015682,
|
||||
GasUsed: 0,
|
||||
|
||||
@@ -252,8 +252,8 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) {
|
||||
ParentHash: hash,
|
||||
Difficulty: big.NewInt(1),
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
TxHash: types.EmptyRootHash,
|
||||
ReceiptHash: types.EmptyRootHash,
|
||||
TxHash: types.EmptyTxsHash,
|
||||
ReceiptHash: types.EmptyReceiptsHash,
|
||||
}
|
||||
hash = header.Hash()
|
||||
|
||||
|
||||
@@ -199,10 +199,10 @@ type BlockChain struct {
|
||||
// Readers don't need to take it, they can just read the database.
|
||||
chainmu *syncx.ClosableMutex
|
||||
|
||||
currentBlock atomic.Value // Current head of the block chain
|
||||
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
|
||||
currentFinalizedBlock atomic.Value // Current finalized head
|
||||
currentSafeBlock atomic.Value // Current safe head
|
||||
currentBlock atomic.Pointer[types.Header] // Current head of the chain
|
||||
currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync
|
||||
currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block
|
||||
currentSafeBlock atomic.Pointer[types.Header] // Latest (consensus) safe block
|
||||
|
||||
bodyCache *lru.Cache[common.Hash, *types.Body]
|
||||
bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue]
|
||||
@@ -289,11 +289,10 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
return nil, ErrNoGenesis
|
||||
}
|
||||
|
||||
var nilBlock *types.Block
|
||||
bc.currentBlock.Store(nilBlock)
|
||||
bc.currentFastBlock.Store(nilBlock)
|
||||
bc.currentFinalizedBlock.Store(nilBlock)
|
||||
bc.currentSafeBlock.Store(nilBlock)
|
||||
bc.currentBlock.Store(nil)
|
||||
bc.currentSnapBlock.Store(nil)
|
||||
bc.currentFinalBlock.Store(nil)
|
||||
bc.currentSafeBlock.Store(nil)
|
||||
|
||||
// If Geth is initialized with an external ancient store, re-initialize the
|
||||
// missing chain indexes and chain flags. This procedure can survive crash
|
||||
@@ -307,7 +306,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
}
|
||||
// Make sure the state associated with the block is available
|
||||
head := bc.CurrentBlock()
|
||||
if !bc.HasState(head.Root()) {
|
||||
if !bc.HasState(head.Root) {
|
||||
// Head state is missing, before the state recovery, find out the
|
||||
// disk layer point of snapshot(if it's enabled). Make sure the
|
||||
// rewound point is lower than disk layer.
|
||||
@@ -316,9 +315,9 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
diskRoot = rawdb.ReadSnapshotRoot(bc.db)
|
||||
}
|
||||
if diskRoot != (common.Hash{}) {
|
||||
log.Warn("Head state missing, repairing", "number", head.Number(), "hash", head.Hash(), "snaproot", diskRoot)
|
||||
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "snaproot", diskRoot)
|
||||
|
||||
snapDisk, err := bc.setHeadBeyondRoot(head.NumberU64(), 0, diskRoot, true)
|
||||
snapDisk, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, diskRoot, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -327,13 +326,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
rawdb.WriteSnapshotRecoveryNumber(bc.db, snapDisk)
|
||||
}
|
||||
} else {
|
||||
log.Warn("Head state missing, repairing", "number", head.Number(), "hash", head.Hash())
|
||||
if _, err := bc.setHeadBeyondRoot(head.NumberU64(), 0, common.Hash{}, true); err != nil {
|
||||
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash())
|
||||
if _, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, common.Hash{}, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a previous crash in SetHead doesn't leave extra ancients
|
||||
if frozen, err := bc.db.Ancients(); err == nil && frozen > 0 {
|
||||
var (
|
||||
@@ -344,18 +342,18 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
// blockchain repair. If the head full block is even lower than the ancient
|
||||
// chain, truncate the ancient store.
|
||||
fullBlock := bc.CurrentBlock()
|
||||
if fullBlock != nil && fullBlock.Hash() != bc.genesisBlock.Hash() && fullBlock.NumberU64() < frozen-1 {
|
||||
if fullBlock != nil && fullBlock.Hash() != bc.genesisBlock.Hash() && fullBlock.Number.Uint64() < frozen-1 {
|
||||
needRewind = true
|
||||
low = fullBlock.NumberU64()
|
||||
low = fullBlock.Number.Uint64()
|
||||
}
|
||||
// In fast sync, it may happen that ancient data has been written to the
|
||||
// ancient store, but the LastFastBlock has not been updated, truncate the
|
||||
// extra data here.
|
||||
fastBlock := bc.CurrentFastBlock()
|
||||
if fastBlock != nil && fastBlock.NumberU64() < frozen-1 {
|
||||
snapBlock := bc.CurrentSnapBlock()
|
||||
if snapBlock != nil && snapBlock.Number.Uint64() < frozen-1 {
|
||||
needRewind = true
|
||||
if fastBlock.NumberU64() < low || low == 0 {
|
||||
low = fastBlock.NumberU64()
|
||||
if snapBlock.Number.Uint64() < low || low == 0 {
|
||||
low = snapBlock.Number.Uint64()
|
||||
}
|
||||
}
|
||||
if needRewind {
|
||||
@@ -395,8 +393,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
var recover bool
|
||||
|
||||
head := bc.CurrentBlock()
|
||||
if layer := rawdb.ReadSnapshotRecoveryNumber(bc.db); layer != nil && *layer >= head.NumberU64() {
|
||||
log.Warn("Enabling snapshot recovery", "chainhead", head.NumberU64(), "diskbase", *layer)
|
||||
if layer := rawdb.ReadSnapshotRecoveryNumber(bc.db); layer != nil && *layer >= head.Number.Uint64() {
|
||||
log.Warn("Enabling snapshot recovery", "chainhead", head.Number, "diskbase", *layer)
|
||||
recover = true
|
||||
}
|
||||
snapconfig := snapshot.Config{
|
||||
@@ -405,7 +403,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
NoBuild: bc.cacheConfig.SnapshotNoBuild,
|
||||
AsyncBuild: !bc.cacheConfig.SnapshotWait,
|
||||
}
|
||||
bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root())
|
||||
bc.snaps, _ = snapshot.New(snapconfig, bc.db, bc.triedb, head.Root)
|
||||
}
|
||||
|
||||
// Start future block processor.
|
||||
@@ -469,32 +467,32 @@ func (bc *BlockChain) loadLastState() error {
|
||||
return bc.Reset()
|
||||
}
|
||||
// Make sure the entire head block is available
|
||||
currentBlock := bc.GetBlockByHash(head)
|
||||
if currentBlock == nil {
|
||||
headBlock := bc.GetBlockByHash(head)
|
||||
if headBlock == nil {
|
||||
// Corrupt or empty database, init from scratch
|
||||
log.Warn("Head block missing, resetting chain", "hash", head)
|
||||
return bc.Reset()
|
||||
}
|
||||
// Everything seems to be fine, set as the head block
|
||||
bc.currentBlock.Store(currentBlock)
|
||||
headBlockGauge.Update(int64(currentBlock.NumberU64()))
|
||||
bc.currentBlock.Store(headBlock.Header())
|
||||
headBlockGauge.Update(int64(headBlock.NumberU64()))
|
||||
|
||||
// Restore the last known head header
|
||||
currentHeader := currentBlock.Header()
|
||||
headHeader := headBlock.Header()
|
||||
if head := rawdb.ReadHeadHeaderHash(bc.db); head != (common.Hash{}) {
|
||||
if header := bc.GetHeaderByHash(head); header != nil {
|
||||
currentHeader = header
|
||||
headHeader = header
|
||||
}
|
||||
}
|
||||
bc.hc.SetCurrentHeader(currentHeader)
|
||||
bc.hc.SetCurrentHeader(headHeader)
|
||||
|
||||
// Restore the last known head fast block
|
||||
bc.currentFastBlock.Store(currentBlock)
|
||||
headFastBlockGauge.Update(int64(currentBlock.NumberU64()))
|
||||
bc.currentSnapBlock.Store(headBlock.Header())
|
||||
headFastBlockGauge.Update(int64(headBlock.NumberU64()))
|
||||
|
||||
if head := rawdb.ReadHeadFastBlockHash(bc.db); head != (common.Hash{}) {
|
||||
if block := bc.GetBlockByHash(head); block != nil {
|
||||
bc.currentFastBlock.Store(block)
|
||||
bc.currentSnapBlock.Store(block.Header())
|
||||
headFastBlockGauge.Update(int64(block.NumberU64()))
|
||||
}
|
||||
}
|
||||
@@ -504,27 +502,31 @@ func (bc *BlockChain) loadLastState() error {
|
||||
// known finalized block on startup
|
||||
if head := rawdb.ReadFinalizedBlockHash(bc.db); head != (common.Hash{}) {
|
||||
if block := bc.GetBlockByHash(head); block != nil {
|
||||
bc.currentFinalizedBlock.Store(block)
|
||||
bc.currentFinalBlock.Store(block.Header())
|
||||
headFinalizedBlockGauge.Update(int64(block.NumberU64()))
|
||||
bc.currentSafeBlock.Store(block)
|
||||
bc.currentSafeBlock.Store(block.Header())
|
||||
headSafeBlockGauge.Update(int64(block.NumberU64()))
|
||||
}
|
||||
}
|
||||
// Issue a status log for the user
|
||||
currentFastBlock := bc.CurrentFastBlock()
|
||||
currentFinalizedBlock := bc.CurrentFinalizedBlock()
|
||||
var (
|
||||
currentSnapBlock = bc.CurrentSnapBlock()
|
||||
currentFinalBlock = bc.CurrentFinalBlock()
|
||||
|
||||
headerTd := bc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64())
|
||||
blockTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
|
||||
fastTd := bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64())
|
||||
|
||||
log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(int64(currentHeader.Time), 0)))
|
||||
log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(currentBlock.Time()), 0)))
|
||||
log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "td", fastTd, "age", common.PrettyAge(time.Unix(int64(currentFastBlock.Time()), 0)))
|
||||
|
||||
if currentFinalizedBlock != nil {
|
||||
finalTd := bc.GetTd(currentFinalizedBlock.Hash(), currentFinalizedBlock.NumberU64())
|
||||
log.Info("Loaded most recent local finalized block", "number", currentFinalizedBlock.Number(), "hash", currentFinalizedBlock.Hash(), "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalizedBlock.Time()), 0)))
|
||||
headerTd = bc.GetTd(headHeader.Hash(), headHeader.Number.Uint64())
|
||||
blockTd = bc.GetTd(headBlock.Hash(), headBlock.NumberU64())
|
||||
)
|
||||
if headHeader.Hash() != headBlock.Hash() {
|
||||
log.Info("Loaded most recent local header", "number", headHeader.Number, "hash", headHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(int64(headHeader.Time), 0)))
|
||||
}
|
||||
log.Info("Loaded most recent local block", "number", headBlock.Number(), "hash", headBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(headBlock.Time()), 0)))
|
||||
if headBlock.Hash() != currentSnapBlock.Hash() {
|
||||
fastTd := bc.GetTd(currentSnapBlock.Hash(), currentSnapBlock.Number.Uint64())
|
||||
log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "td", fastTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0)))
|
||||
}
|
||||
if currentFinalBlock != nil {
|
||||
finalTd := bc.GetTd(currentFinalBlock.Hash(), currentFinalBlock.Number.Uint64())
|
||||
log.Info("Loaded most recent local finalized block", "number", currentFinalBlock.Number, "hash", currentFinalBlock.Hash(), "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalBlock.Time), 0)))
|
||||
}
|
||||
if pivot := rawdb.ReadLastPivotNumber(bc.db); pivot != nil {
|
||||
log.Info("Loaded last fast-sync pivot marker", "number", *pivot)
|
||||
@@ -540,7 +542,16 @@ func (bc *BlockChain) SetHead(head uint64) error {
|
||||
return err
|
||||
}
|
||||
// Send chain head event to update the transaction pool
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Block: bc.CurrentBlock()})
|
||||
header := bc.CurrentBlock()
|
||||
block := bc.GetBlock(header.Hash(), header.Number.Uint64())
|
||||
if block == nil {
|
||||
// This should never happen. In practice, previsouly currentBlock
|
||||
// contained the entire block whereas now only a "marker", so there
|
||||
// is an ever so slight chance for a race we should handle.
|
||||
log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash())
|
||||
return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4])
|
||||
}
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Block: block})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -553,16 +564,25 @@ func (bc *BlockChain) SetHeadWithTimestamp(timestamp uint64) error {
|
||||
return err
|
||||
}
|
||||
// Send chain head event to update the transaction pool
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Block: bc.CurrentBlock()})
|
||||
header := bc.CurrentBlock()
|
||||
block := bc.GetBlock(header.Hash(), header.Number.Uint64())
|
||||
if block == nil {
|
||||
// This should never happen. In practice, previsouly currentBlock
|
||||
// contained the entire block whereas now only a "marker", so there
|
||||
// is an ever so slight chance for a race we should handle.
|
||||
log.Error("Current block not found in database", "block", header.Number, "hash", header.Hash())
|
||||
return fmt.Errorf("current block missing: #%d [%x..]", header.Number, header.Hash().Bytes()[:4])
|
||||
}
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Block: block})
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetFinalized sets the finalized block.
|
||||
func (bc *BlockChain) SetFinalized(block *types.Block) {
|
||||
bc.currentFinalizedBlock.Store(block)
|
||||
if block != nil {
|
||||
rawdb.WriteFinalizedBlockHash(bc.db, block.Hash())
|
||||
headFinalizedBlockGauge.Update(int64(block.NumberU64()))
|
||||
func (bc *BlockChain) SetFinalized(header *types.Header) {
|
||||
bc.currentFinalBlock.Store(header)
|
||||
if header != nil {
|
||||
rawdb.WriteFinalizedBlockHash(bc.db, header.Hash())
|
||||
headFinalizedBlockGauge.Update(int64(header.Number.Uint64()))
|
||||
} else {
|
||||
rawdb.WriteFinalizedBlockHash(bc.db, common.Hash{})
|
||||
headFinalizedBlockGauge.Update(0)
|
||||
@@ -570,10 +590,10 @@ func (bc *BlockChain) SetFinalized(block *types.Block) {
|
||||
}
|
||||
|
||||
// SetSafe sets the safe block.
|
||||
func (bc *BlockChain) SetSafe(block *types.Block) {
|
||||
bc.currentSafeBlock.Store(block)
|
||||
if block != nil {
|
||||
headSafeBlockGauge.Update(int64(block.NumberU64()))
|
||||
func (bc *BlockChain) SetSafe(header *types.Header) {
|
||||
bc.currentSafeBlock.Store(header)
|
||||
if header != nil {
|
||||
headSafeBlockGauge.Update(int64(header.Number.Uint64()))
|
||||
} else {
|
||||
headSafeBlockGauge.Update(0)
|
||||
}
|
||||
@@ -609,7 +629,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
||||
// Rewind the blockchain, ensuring we don't end up with a stateless head
|
||||
// block. Note, depth equality is permitted to allow using SetHead as a
|
||||
// chain reparation mechanism without deleting any data!
|
||||
if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() <= currentBlock.NumberU64() {
|
||||
if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() <= currentBlock.Number.Uint64() {
|
||||
newHeadBlock := bc.GetBlock(header.Hash(), header.Number.Uint64())
|
||||
if newHeadBlock == nil {
|
||||
log.Error("Gap in the chain, rewinding to genesis", "number", header.Number, "hash", header.Hash())
|
||||
@@ -667,27 +687,27 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
||||
// In theory we should update all in-memory markers in the
|
||||
// last step, however the direction of SetHead is from high
|
||||
// to low, so it's safe to update in-memory markers directly.
|
||||
bc.currentBlock.Store(newHeadBlock)
|
||||
bc.currentBlock.Store(newHeadBlock.Header())
|
||||
headBlockGauge.Update(int64(newHeadBlock.NumberU64()))
|
||||
}
|
||||
// Rewind the fast block in a simpleton way to the target head
|
||||
if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock != nil && header.Number.Uint64() < currentFastBlock.NumberU64() {
|
||||
newHeadFastBlock := bc.GetBlock(header.Hash(), header.Number.Uint64())
|
||||
if currentSnapBlock := bc.CurrentSnapBlock(); currentSnapBlock != nil && header.Number.Uint64() < currentSnapBlock.Number.Uint64() {
|
||||
newHeadSnapBlock := bc.GetBlock(header.Hash(), header.Number.Uint64())
|
||||
// If either blocks reached nil, reset to the genesis state
|
||||
if newHeadFastBlock == nil {
|
||||
newHeadFastBlock = bc.genesisBlock
|
||||
if newHeadSnapBlock == nil {
|
||||
newHeadSnapBlock = bc.genesisBlock
|
||||
}
|
||||
rawdb.WriteHeadFastBlockHash(db, newHeadFastBlock.Hash())
|
||||
rawdb.WriteHeadFastBlockHash(db, newHeadSnapBlock.Hash())
|
||||
|
||||
// Degrade the chain markers if they are explicitly reverted.
|
||||
// In theory we should update all in-memory markers in the
|
||||
// last step, however the direction of SetHead is from high
|
||||
// to low, so it's safe the update in-memory markers directly.
|
||||
bc.currentFastBlock.Store(newHeadFastBlock)
|
||||
headFastBlockGauge.Update(int64(newHeadFastBlock.NumberU64()))
|
||||
bc.currentSnapBlock.Store(newHeadSnapBlock.Header())
|
||||
headFastBlockGauge.Update(int64(newHeadSnapBlock.NumberU64()))
|
||||
}
|
||||
var (
|
||||
headHeader = bc.CurrentBlock().Header()
|
||||
headHeader = bc.CurrentBlock()
|
||||
headNumber = headHeader.Number.Uint64()
|
||||
)
|
||||
// If setHead underflown the freezer threshold and the block processing
|
||||
@@ -723,7 +743,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
||||
// If SetHead was only called as a chain reparation method, try to skip
|
||||
// touching the header chain altogether, unless the freezer is broken
|
||||
if repair {
|
||||
if target, force := updateFn(bc.db, bc.CurrentBlock().Header()); force {
|
||||
if target, force := updateFn(bc.db, bc.CurrentBlock()); force {
|
||||
bc.hc.SetHead(target.Number.Uint64(), updateFn, delFn)
|
||||
}
|
||||
} else {
|
||||
@@ -746,15 +766,14 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
||||
bc.futureBlocks.Purge()
|
||||
|
||||
// Clear safe block, finalized block if needed
|
||||
if safe := bc.CurrentSafeBlock(); safe != nil && head < safe.NumberU64() {
|
||||
if safe := bc.CurrentSafeBlock(); safe != nil && head < safe.Number.Uint64() {
|
||||
log.Warn("SetHead invalidated safe block")
|
||||
bc.SetSafe(nil)
|
||||
}
|
||||
if finalized := bc.CurrentFinalizedBlock(); finalized != nil && head < finalized.NumberU64() {
|
||||
if finalized := bc.CurrentFinalBlock(); finalized != nil && head < finalized.Number.Uint64() {
|
||||
log.Error("SetHead invalidated finalized block")
|
||||
bc.SetFinalized(nil)
|
||||
}
|
||||
|
||||
return rootNumber, bc.loadLastState()
|
||||
}
|
||||
|
||||
@@ -774,7 +793,7 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error {
|
||||
if !bc.chainmu.TryLock() {
|
||||
return errChainStopped
|
||||
}
|
||||
bc.currentBlock.Store(block)
|
||||
bc.currentBlock.Store(block.Header())
|
||||
headBlockGauge.Update(int64(block.NumberU64()))
|
||||
bc.chainmu.Unlock()
|
||||
|
||||
@@ -815,18 +834,18 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {
|
||||
|
||||
// Last update all in-memory chain markers
|
||||
bc.genesisBlock = genesis
|
||||
bc.currentBlock.Store(bc.genesisBlock)
|
||||
bc.currentBlock.Store(bc.genesisBlock.Header())
|
||||
headBlockGauge.Update(int64(bc.genesisBlock.NumberU64()))
|
||||
bc.hc.SetGenesis(bc.genesisBlock.Header())
|
||||
bc.hc.SetCurrentHeader(bc.genesisBlock.Header())
|
||||
bc.currentFastBlock.Store(bc.genesisBlock)
|
||||
bc.currentSnapBlock.Store(bc.genesisBlock.Header())
|
||||
headFastBlockGauge.Update(int64(bc.genesisBlock.NumberU64()))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Export writes the active chain to the given writer.
|
||||
func (bc *BlockChain) Export(w io.Writer) error {
|
||||
return bc.ExportN(w, uint64(0), bc.CurrentBlock().NumberU64())
|
||||
return bc.ExportN(w, uint64(0), bc.CurrentBlock().Number.Uint64())
|
||||
}
|
||||
|
||||
// ExportN writes a subset of the active chain to the given writer.
|
||||
@@ -883,10 +902,10 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) {
|
||||
// Update all in-memory chain markers in the last step
|
||||
bc.hc.SetCurrentHeader(block.Header())
|
||||
|
||||
bc.currentFastBlock.Store(block)
|
||||
bc.currentSnapBlock.Store(block.Header())
|
||||
headFastBlockGauge.Update(int64(block.NumberU64()))
|
||||
|
||||
bc.currentBlock.Store(block)
|
||||
bc.currentBlock.Store(block.Header())
|
||||
headBlockGauge.Update(int64(block.NumberU64()))
|
||||
}
|
||||
|
||||
@@ -927,7 +946,7 @@ func (bc *BlockChain) Stop() {
|
||||
var snapBase common.Hash
|
||||
if bc.snaps != nil {
|
||||
var err error
|
||||
if snapBase, err = bc.snaps.Journal(bc.CurrentBlock().Root()); err != nil {
|
||||
if snapBase, err = bc.snaps.Journal(bc.CurrentBlock().Root); err != nil {
|
||||
log.Error("Failed to journal state snapshot", "err", err)
|
||||
}
|
||||
}
|
||||
@@ -941,7 +960,7 @@ func (bc *BlockChain) Stop() {
|
||||
triedb := bc.triedb
|
||||
|
||||
for _, offset := range []uint64{0, 1, TriesInMemory - 1} {
|
||||
if number := bc.CurrentBlock().NumberU64(); number > offset {
|
||||
if number := bc.CurrentBlock().Number.Uint64(); number > offset {
|
||||
recent := bc.GetBlockByNumber(number - offset)
|
||||
|
||||
log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root())
|
||||
@@ -1059,7 +1078,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||
|
||||
// Rewind may have occurred, skip in that case.
|
||||
if bc.CurrentHeader().Number.Cmp(head.Number()) >= 0 {
|
||||
reorg, err := bc.forker.ReorgNeeded(bc.CurrentFastBlock().Header(), head.Header())
|
||||
reorg, err := bc.forker.ReorgNeeded(bc.CurrentSnapBlock(), head.Header())
|
||||
if err != nil {
|
||||
log.Warn("Reorg failed", "err", err)
|
||||
return false
|
||||
@@ -1067,13 +1086,12 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||
return false
|
||||
}
|
||||
rawdb.WriteHeadFastBlockHash(bc.db, head.Hash())
|
||||
bc.currentFastBlock.Store(head)
|
||||
bc.currentSnapBlock.Store(head.Header())
|
||||
headFastBlockGauge.Update(int64(head.NumberU64()))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// writeAncient writes blockchain and corresponding receipt chain into ancient store.
|
||||
//
|
||||
// this function only accepts canonical chain data. All side chain will be reverted
|
||||
@@ -1135,8 +1153,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||
if batch.ValueSize() > ethdb.IdealBatchSize || i == len(blockChain)-1 {
|
||||
size += int64(batch.ValueSize())
|
||||
if err = batch.Write(); err != nil {
|
||||
fastBlock := bc.CurrentFastBlock().NumberU64()
|
||||
if err := bc.db.TruncateHead(fastBlock + 1); err != nil {
|
||||
snapBlock := bc.CurrentSnapBlock().Number.Uint64()
|
||||
if err := bc.db.TruncateHead(snapBlock + 1); err != nil {
|
||||
log.Error("Can't truncate ancient store after failed insert", "err", err)
|
||||
}
|
||||
return 0, err
|
||||
@@ -1150,11 +1168,11 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||
return 0, err
|
||||
}
|
||||
// Update the current fast block because all block data is now present in DB.
|
||||
previousFastBlock := bc.CurrentFastBlock().NumberU64()
|
||||
previousSnapBlock := bc.CurrentSnapBlock().Number.Uint64()
|
||||
if !updateHead(blockChain[len(blockChain)-1]) {
|
||||
// We end up here if the header chain has reorg'ed, and the blocks/receipts
|
||||
// don't match the canonical chain.
|
||||
if err := bc.db.TruncateHead(previousFastBlock + 1); err != nil {
|
||||
if err := bc.db.TruncateHead(previousSnapBlock + 1); err != nil {
|
||||
log.Error("Can't truncate ancient store after failed insert", "err", err)
|
||||
}
|
||||
return 0, errSideChainReceipts
|
||||
@@ -1278,7 +1296,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||
if stats.ignored > 0 {
|
||||
context = append(context, []interface{}{"ignored", stats.ignored}...)
|
||||
}
|
||||
log.Info("Imported new block receipts", context...)
|
||||
log.Debug("Imported new block receipts", context...)
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
@@ -1414,7 +1432,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
|
||||
return NonStatTy, err
|
||||
}
|
||||
currentBlock := bc.CurrentBlock()
|
||||
reorg, err := bc.forker.ReorgNeeded(currentBlock.Header(), block.Header())
|
||||
reorg, err := bc.forker.ReorgNeeded(currentBlock, block.Header())
|
||||
if err != nil {
|
||||
return NonStatTy, err
|
||||
}
|
||||
@@ -1562,7 +1580,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
|
||||
current = bc.CurrentBlock()
|
||||
)
|
||||
for block != nil && bc.skipBlock(err, it) {
|
||||
reorg, err = bc.forker.ReorgNeeded(current.Header(), block.Header())
|
||||
reorg, err = bc.forker.ReorgNeeded(current, block.Header())
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
}
|
||||
@@ -1572,7 +1590,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool)
|
||||
// In eth2 the forker always returns true for reorg decision (blindly trusting
|
||||
// the external consensus engine), but in order to prevent the unnecessary
|
||||
// reorgs when importing known blocks, the special case is handled here.
|
||||
if block.NumberU64() > current.NumberU64() || bc.GetCanonicalHash(block.NumberU64()) != block.Hash() {
|
||||
if block.NumberU64() > current.Number.Uint64() || bc.GetCanonicalHash(block.NumberU64()) != block.Hash() {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -1872,7 +1890,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
||||
err := consensus.ErrPrunedAncestor
|
||||
for ; block != nil && errors.Is(err, consensus.ErrPrunedAncestor); block, err = it.next() {
|
||||
// Check the canonical state root for that number
|
||||
if number := block.NumberU64(); current.NumberU64() >= number {
|
||||
if number := block.NumberU64(); current.Number.Uint64() >= number {
|
||||
canonical := bc.GetBlockByNumber(number)
|
||||
if canonical != nil && canonical.Hash() == block.Hash() {
|
||||
// Not a sidechain block, this is a re-import of a canon block which has it's state pruned
|
||||
@@ -1922,12 +1940,12 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
||||
//
|
||||
// If the externTd was larger than our local TD, we now need to reimport the previous
|
||||
// blocks to regenerate the required state
|
||||
reorg, err := bc.forker.ReorgNeeded(current.Header(), lastBlock.Header())
|
||||
reorg, err := bc.forker.ReorgNeeded(current, lastBlock.Header())
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
}
|
||||
if !reorg {
|
||||
localTd := bc.GetTd(current.Hash(), current.NumberU64())
|
||||
localTd := bc.GetTd(current.Hash(), current.Number.Uint64())
|
||||
log.Info("Sidechain written to disk", "start", it.first().NumberU64(), "end", it.previous().Number, "sidetd", externTd, "localtd", localTd)
|
||||
return it.index, err
|
||||
}
|
||||
@@ -2031,7 +2049,7 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error)
|
||||
// the processing of a block. These logs are later announced as deleted or reborn.
|
||||
func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log {
|
||||
receipts := rawdb.ReadRawReceipts(bc.db, b.Hash(), b.NumberU64())
|
||||
receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.Transactions())
|
||||
receipts.DeriveFields(bc.chainConfig, b.Hash(), b.NumberU64(), b.BaseFee(), b.Transactions())
|
||||
|
||||
var logs []*types.Log
|
||||
for _, receipt := range receipts {
|
||||
@@ -2051,7 +2069,7 @@ func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log {
|
||||
// potential missing transactions and post an event about them.
|
||||
// Note the new head block won't be processed here, callers need to handle it
|
||||
// externally.
|
||||
func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||
func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
|
||||
var (
|
||||
newChain types.Blocks
|
||||
oldChain types.Blocks
|
||||
@@ -2060,6 +2078,12 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||
deletedTxs []common.Hash
|
||||
addedTxs []common.Hash
|
||||
)
|
||||
oldBlock := bc.GetBlock(oldHead.Hash(), oldHead.Number.Uint64())
|
||||
if oldBlock == nil {
|
||||
return errors.New("current head block missing")
|
||||
}
|
||||
newBlock := newHead
|
||||
|
||||
// Reduce the longer chain to the same number as the shorter one
|
||||
if oldBlock.NumberU64() > newBlock.NumberU64() {
|
||||
// Old chain is longer, gather all transactions and logs as deleted ones
|
||||
@@ -2076,10 +2100,10 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
||||
}
|
||||
}
|
||||
if oldBlock == nil {
|
||||
return fmt.Errorf("invalid old chain")
|
||||
return errors.New("invalid old chain")
|
||||
}
|
||||
if newBlock == nil {
|
||||
return fmt.Errorf("invalid new chain")
|
||||
return errors.New("invalid new chain")
|
||||
}
|
||||
// Both sides of the reorg are at the same number, reduce both until the common
|
||||
// ancestor is found
|
||||
|
||||
@@ -40,26 +40,26 @@ func (bc *BlockChain) CurrentHeader() *types.Header {
|
||||
|
||||
// CurrentBlock retrieves the current head block of the canonical chain. The
|
||||
// block is retrieved from the blockchain's internal cache.
|
||||
func (bc *BlockChain) CurrentBlock() *types.Block {
|
||||
return bc.currentBlock.Load().(*types.Block)
|
||||
func (bc *BlockChain) CurrentBlock() *types.Header {
|
||||
return bc.currentBlock.Load()
|
||||
}
|
||||
|
||||
// CurrentFastBlock retrieves the current fast-sync head block of the canonical
|
||||
// CurrentSnapBlock retrieves the current snap-sync head block of the canonical
|
||||
// chain. The block is retrieved from the blockchain's internal cache.
|
||||
func (bc *BlockChain) CurrentFastBlock() *types.Block {
|
||||
return bc.currentFastBlock.Load().(*types.Block)
|
||||
func (bc *BlockChain) CurrentSnapBlock() *types.Header {
|
||||
return bc.currentSnapBlock.Load()
|
||||
}
|
||||
|
||||
// CurrentFinalizedBlock retrieves the current finalized block of the canonical
|
||||
// CurrentFinalBlock retrieves the current finalized block of the canonical
|
||||
// chain. The block is retrieved from the blockchain's internal cache.
|
||||
func (bc *BlockChain) CurrentFinalizedBlock() *types.Block {
|
||||
return bc.currentFinalizedBlock.Load().(*types.Block)
|
||||
func (bc *BlockChain) CurrentFinalBlock() *types.Header {
|
||||
return bc.currentFinalBlock.Load()
|
||||
}
|
||||
|
||||
// CurrentSafeBlock retrieves the current safe block of the canonical
|
||||
// chain. The block is retrieved from the blockchain's internal cache.
|
||||
func (bc *BlockChain) CurrentSafeBlock() *types.Block {
|
||||
return bc.currentSafeBlock.Load().(*types.Block)
|
||||
func (bc *BlockChain) CurrentSafeBlock() *types.Header {
|
||||
return bc.currentSafeBlock.Load()
|
||||
}
|
||||
|
||||
// HasHeader checks if a block header is present in the database or not, caching
|
||||
@@ -315,7 +315,7 @@ func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
|
||||
|
||||
// State returns a new mutable state based on the current HEAD block.
|
||||
func (bc *BlockChain) State() (*state.StateDB, error) {
|
||||
return bc.StateAt(bc.CurrentBlock().Root())
|
||||
return bc.StateAt(bc.CurrentBlock().Root)
|
||||
}
|
||||
|
||||
// StateAt returns a new mutable state based on a particular point in time.
|
||||
@@ -351,7 +351,7 @@ func (bc *BlockChain) StateCache() state.Database {
|
||||
|
||||
// GasLimit returns the gas limit of the current HEAD block.
|
||||
func (bc *BlockChain) GasLimit() uint64 {
|
||||
return bc.CurrentBlock().GasLimit()
|
||||
return bc.CurrentBlock().GasLimit
|
||||
}
|
||||
|
||||
// Genesis retrieves the chain's genesis block.
|
||||
|
||||
@@ -1857,11 +1857,11 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||
if head := newChain.CurrentHeader(); head.Number.Uint64() != tt.expHeadHeader {
|
||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, tt.expHeadHeader)
|
||||
}
|
||||
if head := newChain.CurrentFastBlock(); head.NumberU64() != tt.expHeadFastBlock {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadFastBlock)
|
||||
if head := newChain.CurrentSnapBlock(); head.Number.Uint64() != tt.expHeadFastBlock {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, tt.expHeadFastBlock)
|
||||
}
|
||||
if head := newChain.CurrentBlock(); head.NumberU64() != tt.expHeadBlock {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadBlock)
|
||||
if head := newChain.CurrentBlock(); head.Number.Uint64() != tt.expHeadBlock {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.Number, tt.expHeadBlock)
|
||||
}
|
||||
if frozen, err := db.(freezer).Ancients(); err != nil {
|
||||
t.Errorf("Failed to retrieve ancient count: %v\n", err)
|
||||
@@ -1973,11 +1973,11 @@ func TestIssue23496(t *testing.T) {
|
||||
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
|
||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
|
||||
}
|
||||
if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), uint64(4))
|
||||
if head := chain.CurrentSnapBlock(); head.Number.Uint64() != uint64(4) {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, uint64(4))
|
||||
}
|
||||
if head := chain.CurrentBlock(); head.NumberU64() != uint64(1) {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), uint64(1))
|
||||
if head := chain.CurrentBlock(); head.Number.Uint64() != uint64(1) {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.Number, uint64(1))
|
||||
}
|
||||
|
||||
// Reinsert B2-B4
|
||||
@@ -1987,11 +1987,11 @@ func TestIssue23496(t *testing.T) {
|
||||
if head := chain.CurrentHeader(); head.Number.Uint64() != uint64(4) {
|
||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, 4)
|
||||
}
|
||||
if head := chain.CurrentFastBlock(); head.NumberU64() != uint64(4) {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), uint64(4))
|
||||
if head := chain.CurrentSnapBlock(); head.Number.Uint64() != uint64(4) {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, uint64(4))
|
||||
}
|
||||
if head := chain.CurrentBlock(); head.NumberU64() != uint64(4) {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), uint64(4))
|
||||
if head := chain.CurrentBlock(); head.Number.Uint64() != uint64(4) {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.Number, uint64(4))
|
||||
}
|
||||
if layer := chain.Snapshots().Snapshot(blocks[2].Root()); layer == nil {
|
||||
t.Error("Failed to regenerate the snapshot of known state")
|
||||
|
||||
@@ -2047,11 +2047,11 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||
if head := chain.CurrentHeader(); head.Number.Uint64() != tt.expHeadHeader {
|
||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, tt.expHeadHeader)
|
||||
}
|
||||
if head := chain.CurrentFastBlock(); head.NumberU64() != tt.expHeadFastBlock {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadFastBlock)
|
||||
if head := chain.CurrentSnapBlock(); head.Number.Uint64() != tt.expHeadFastBlock {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, tt.expHeadFastBlock)
|
||||
}
|
||||
if head := chain.CurrentBlock(); head.NumberU64() != tt.expHeadBlock {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), tt.expHeadBlock)
|
||||
if head := chain.CurrentBlock(); head.Number.Uint64() != tt.expHeadBlock {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.Number, tt.expHeadBlock)
|
||||
}
|
||||
if frozen, err := db.(freezer).Ancients(); err != nil {
|
||||
t.Errorf("Failed to retrieve ancient count: %v\n", err)
|
||||
|
||||
@@ -136,11 +136,11 @@ func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks [
|
||||
if head := chain.CurrentHeader(); head.Number.Uint64() != basic.expHeadHeader {
|
||||
t.Errorf("Head header mismatch: have %d, want %d", head.Number, basic.expHeadHeader)
|
||||
}
|
||||
if head := chain.CurrentFastBlock(); head.NumberU64() != basic.expHeadFastBlock {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadFastBlock)
|
||||
if head := chain.CurrentSnapBlock(); head.Number.Uint64() != basic.expHeadFastBlock {
|
||||
t.Errorf("Head fast block mismatch: have %d, want %d", head.Number, basic.expHeadFastBlock)
|
||||
}
|
||||
if head := chain.CurrentBlock(); head.NumberU64() != basic.expHeadBlock {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadBlock)
|
||||
if head := chain.CurrentBlock(); head.Number.Uint64() != basic.expHeadBlock {
|
||||
t.Errorf("Head block mismatch: have %d, want %d", head.Number, basic.expHeadBlock)
|
||||
}
|
||||
|
||||
// Check the disk layer, ensure they are matched
|
||||
|
||||
@@ -109,7 +109,7 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara
|
||||
headerChainB []*types.Header
|
||||
)
|
||||
if full {
|
||||
blockChainB = makeBlockChain(blockchain2.chainConfig, blockchain2.CurrentBlock(), n, ethash.NewFaker(), genDb, forkSeed)
|
||||
blockChainB = makeBlockChain(blockchain2.chainConfig, blockchain2.GetBlockByHash(blockchain2.CurrentBlock().Hash()), n, ethash.NewFaker(), genDb, forkSeed)
|
||||
if _, err := blockchain2.InsertChain(blockChainB); err != nil {
|
||||
t.Fatalf("failed to insert forking chain: %v", err)
|
||||
}
|
||||
@@ -124,7 +124,7 @@ func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, compara
|
||||
|
||||
if full {
|
||||
cur := blockchain.CurrentBlock()
|
||||
tdPre = blockchain.GetTd(cur.Hash(), cur.NumberU64())
|
||||
tdPre = blockchain.GetTd(cur.Hash(), cur.Number.Uint64())
|
||||
if err := testBlockChainImport(blockChainB, blockchain); err != nil {
|
||||
t.Fatalf("failed to import forked block chain: %v", err)
|
||||
}
|
||||
@@ -206,7 +206,7 @@ func TestLastBlock(t *testing.T) {
|
||||
}
|
||||
defer blockchain.Stop()
|
||||
|
||||
blocks := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), 1, ethash.NewFullFaker(), genDb, 0)
|
||||
blocks := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 1, ethash.NewFullFaker(), genDb, 0)
|
||||
if _, err := blockchain.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("Failed to insert block: %v", err)
|
||||
}
|
||||
@@ -240,11 +240,11 @@ func testInsertAfterMerge(t *testing.T, blockchain *BlockChain, i, n int, full b
|
||||
|
||||
// Extend the newly created chain
|
||||
if full {
|
||||
blockChainB := makeBlockChain(blockchain2.chainConfig, blockchain2.CurrentBlock(), n, ethash.NewFaker(), genDb, forkSeed)
|
||||
blockChainB := makeBlockChain(blockchain2.chainConfig, blockchain2.GetBlockByHash(blockchain2.CurrentBlock().Hash()), n, ethash.NewFaker(), genDb, forkSeed)
|
||||
if _, err := blockchain2.InsertChain(blockChainB); err != nil {
|
||||
t.Fatalf("failed to insert forking chain: %v", err)
|
||||
}
|
||||
if blockchain2.CurrentBlock().NumberU64() != blockChainB[len(blockChainB)-1].NumberU64() {
|
||||
if blockchain2.CurrentBlock().Number.Uint64() != blockChainB[len(blockChainB)-1].NumberU64() {
|
||||
t.Fatalf("failed to reorg to the given chain")
|
||||
}
|
||||
if blockchain2.CurrentBlock().Hash() != blockChainB[len(blockChainB)-1].Hash() {
|
||||
@@ -477,7 +477,7 @@ func testBrokenChain(t *testing.T, full bool) {
|
||||
|
||||
// Create a forked chain, and try to insert with a missing link
|
||||
if full {
|
||||
chain := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), 5, ethash.NewFaker(), genDb, forkSeed)[1:]
|
||||
chain := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 5, ethash.NewFaker(), genDb, forkSeed)[1:]
|
||||
if err := testBlockChainImport(chain, blockchain); err == nil {
|
||||
t.Errorf("broken block chain not reported")
|
||||
}
|
||||
@@ -527,10 +527,10 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool) {
|
||||
defer blockchain.Stop()
|
||||
|
||||
// Insert an easy and a difficult chain afterwards
|
||||
easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), genDb, len(first), func(i int, b *BlockGen) {
|
||||
easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), ethash.NewFaker(), genDb, len(first), func(i int, b *BlockGen) {
|
||||
b.OffsetTime(first[i])
|
||||
})
|
||||
diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.CurrentBlock(), ethash.NewFaker(), genDb, len(second), func(i int, b *BlockGen) {
|
||||
diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), ethash.NewFaker(), genDb, len(second), func(i int, b *BlockGen) {
|
||||
b.OffsetTime(second[i])
|
||||
})
|
||||
if full {
|
||||
@@ -559,9 +559,9 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool) {
|
||||
// Check that the chain is valid number and link wise
|
||||
if full {
|
||||
prev := blockchain.CurrentBlock()
|
||||
for block := blockchain.GetBlockByNumber(blockchain.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, blockchain.GetBlockByNumber(block.NumberU64()-1) {
|
||||
if prev.ParentHash() != block.Hash() {
|
||||
t.Errorf("parent block hash mismatch: have %x, want %x", prev.ParentHash(), block.Hash())
|
||||
for block := blockchain.GetBlockByNumber(blockchain.CurrentBlock().Number.Uint64() - 1); block.NumberU64() != 0; prev, block = block.Header(), blockchain.GetBlockByNumber(block.NumberU64()-1) {
|
||||
if prev.ParentHash != block.Hash() {
|
||||
t.Errorf("parent block hash mismatch: have %x, want %x", prev.ParentHash, block.Hash())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -576,7 +576,7 @@ func testReorg(t *testing.T, first, second []int64, td int64, full bool) {
|
||||
want := new(big.Int).Add(blockchain.genesisBlock.Difficulty(), big.NewInt(td))
|
||||
if full {
|
||||
cur := blockchain.CurrentBlock()
|
||||
if have := blockchain.GetTd(cur.Hash(), cur.NumberU64()); have.Cmp(want) != 0 {
|
||||
if have := blockchain.GetTd(cur.Hash(), cur.Number.Uint64()); have.Cmp(want) != 0 {
|
||||
t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
|
||||
}
|
||||
} else {
|
||||
@@ -601,7 +601,7 @@ func testBadHashes(t *testing.T, full bool) {
|
||||
|
||||
// Create a chain, ban a hash and try to import
|
||||
if full {
|
||||
blocks := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), 3, ethash.NewFaker(), genDb, 10)
|
||||
blocks := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 3, ethash.NewFaker(), genDb, 10)
|
||||
|
||||
BadHashes[blocks[2].Header().Hash()] = true
|
||||
defer func() { delete(BadHashes, blocks[2].Header().Hash()) }()
|
||||
@@ -633,7 +633,7 @@ func testReorgBadHashes(t *testing.T, full bool) {
|
||||
}
|
||||
// Create a chain, import and ban afterwards
|
||||
headers := makeHeaderChain(blockchain.chainConfig, blockchain.CurrentHeader(), 4, ethash.NewFaker(), genDb, 10)
|
||||
blocks := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), 4, ethash.NewFaker(), genDb, 10)
|
||||
blocks := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), 4, ethash.NewFaker(), genDb, 10)
|
||||
|
||||
if full {
|
||||
if _, err = blockchain.InsertChain(blocks); err != nil {
|
||||
@@ -696,7 +696,7 @@ func testInsertNonceError(t *testing.T, full bool) {
|
||||
failNum uint64
|
||||
)
|
||||
if full {
|
||||
blocks := makeBlockChain(blockchain.chainConfig, blockchain.CurrentBlock(), i, ethash.NewFaker(), genDb, 0)
|
||||
blocks := makeBlockChain(blockchain.chainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), i, ethash.NewFaker(), genDb, 0)
|
||||
|
||||
failAt = rand.Int() % len(blocks)
|
||||
failNum = blocks[failAt].NumberU64()
|
||||
@@ -894,11 +894,11 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||
assert := func(t *testing.T, kind string, chain *BlockChain, header uint64, fast uint64, block uint64) {
|
||||
t.Helper()
|
||||
|
||||
if num := chain.CurrentBlock().NumberU64(); num != block {
|
||||
if num := chain.CurrentBlock().Number.Uint64(); num != block {
|
||||
t.Errorf("%s head block mismatch: have #%v, want #%v", kind, num, block)
|
||||
}
|
||||
if num := chain.CurrentFastBlock().NumberU64(); num != fast {
|
||||
t.Errorf("%s head fast-block mismatch: have #%v, want #%v", kind, num, fast)
|
||||
if num := chain.CurrentSnapBlock().Number.Uint64(); num != fast {
|
||||
t.Errorf("%s head snap-block mismatch: have #%v, want #%v", kind, num, fast)
|
||||
}
|
||||
if num := chain.CurrentHeader().Number.Uint64(); num != header {
|
||||
t.Errorf("%s head header mismatch: have #%v, want #%v", kind, num, header)
|
||||
@@ -1649,13 +1649,13 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) {
|
||||
t.Fatalf("block %d: failed to insert into chain: %v", i, err)
|
||||
}
|
||||
if chain.CurrentBlock().Hash() != chain.CurrentHeader().Hash() {
|
||||
t.Errorf("block %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number(), chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4])
|
||||
t.Errorf("block %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number, chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4])
|
||||
}
|
||||
if _, err := chain.InsertChain(forks[i : i+1]); err != nil {
|
||||
t.Fatalf(" fork %d: failed to insert into chain: %v", i, err)
|
||||
}
|
||||
if chain.CurrentBlock().Hash() != chain.CurrentHeader().Hash() {
|
||||
t.Errorf(" fork %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number(), chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4])
|
||||
t.Errorf(" fork %d: current block/header mismatch: block #%d [%x..], header #%d [%x..]", i, chain.CurrentBlock().Number, chain.CurrentBlock().Hash().Bytes()[:4], chain.CurrentHeader().Number, chain.CurrentHeader().Hash().Bytes()[:4])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1797,11 +1797,11 @@ func TestBlockchainRecovery(t *testing.T) {
|
||||
// Reopen broken blockchain again
|
||||
ancient, _ = NewBlockChain(ancientDb, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
defer ancient.Stop()
|
||||
if num := ancient.CurrentBlock().NumberU64(); num != 0 {
|
||||
if num := ancient.CurrentBlock().Number.Uint64(); num != 0 {
|
||||
t.Errorf("head block mismatch: have #%v, want #%v", num, 0)
|
||||
}
|
||||
if num := ancient.CurrentFastBlock().NumberU64(); num != midBlock.NumberU64() {
|
||||
t.Errorf("head fast-block mismatch: have #%v, want #%v", num, midBlock.NumberU64())
|
||||
if num := ancient.CurrentSnapBlock().Number.Uint64(); num != midBlock.NumberU64() {
|
||||
t.Errorf("head snap-block mismatch: have #%v, want #%v", num, midBlock.NumberU64())
|
||||
}
|
||||
if num := ancient.CurrentHeader().Number.Uint64(); num != midBlock.NumberU64() {
|
||||
t.Errorf("head header mismatch: have #%v, want #%v", num, midBlock.NumberU64())
|
||||
@@ -1820,7 +1820,7 @@ func TestInsertReceiptChainRollback(t *testing.T) {
|
||||
if _, err := tmpChain.InsertChain(sideblocks); err != nil {
|
||||
t.Fatal("processing side chain failed:", err)
|
||||
}
|
||||
t.Log("sidechain head:", tmpChain.CurrentBlock().Number(), tmpChain.CurrentBlock().Hash())
|
||||
t.Log("sidechain head:", tmpChain.CurrentBlock().Number, tmpChain.CurrentBlock().Hash())
|
||||
sidechainReceipts := make([]types.Receipts, len(sideblocks))
|
||||
for i, block := range sideblocks {
|
||||
sidechainReceipts[i] = tmpChain.GetReceiptsByHash(block.Hash())
|
||||
@@ -1829,7 +1829,7 @@ func TestInsertReceiptChainRollback(t *testing.T) {
|
||||
if _, err := tmpChain.InsertChain(canonblocks); err != nil {
|
||||
t.Fatal("processing canon chain failed:", err)
|
||||
}
|
||||
t.Log("canon head:", tmpChain.CurrentBlock().Number(), tmpChain.CurrentBlock().Hash())
|
||||
t.Log("canon head:", tmpChain.CurrentBlock().Number, tmpChain.CurrentBlock().Hash())
|
||||
canonReceipts := make([]types.Receipts, len(canonblocks))
|
||||
for i, block := range canonblocks {
|
||||
canonReceipts[i] = tmpChain.GetReceiptsByHash(block.Hash())
|
||||
@@ -1859,8 +1859,8 @@ func TestInsertReceiptChainRollback(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Fatal("expected error from InsertReceiptChain.")
|
||||
}
|
||||
if ancientChain.CurrentFastBlock().NumberU64() != 0 {
|
||||
t.Fatalf("failed to rollback ancient data, want %d, have %d", 0, ancientChain.CurrentFastBlock().NumberU64())
|
||||
if ancientChain.CurrentSnapBlock().Number.Uint64() != 0 {
|
||||
t.Fatalf("failed to rollback ancient data, want %d, have %d", 0, ancientChain.CurrentSnapBlock().Number)
|
||||
}
|
||||
if frozen, err := ancientChain.db.Ancients(); err != nil || frozen != 1 {
|
||||
t.Fatalf("failed to truncate ancient data, frozen index is %d", frozen)
|
||||
@@ -1871,7 +1871,7 @@ func TestInsertReceiptChainRollback(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("can't import canon chain receipts: %v", err)
|
||||
}
|
||||
if ancientChain.CurrentFastBlock().NumberU64() != canonblocks[len(canonblocks)-1].NumberU64() {
|
||||
if ancientChain.CurrentSnapBlock().Number.Uint64() != canonblocks[len(canonblocks)-1].NumberU64() {
|
||||
t.Fatalf("failed to insert ancient recept chain after rollback")
|
||||
}
|
||||
if frozen, _ := ancientChain.db.Ancients(); frozen != uint64(len(canonblocks))+1 {
|
||||
@@ -1926,7 +1926,7 @@ func TestLowDiffLongChain(t *testing.T) {
|
||||
}
|
||||
// Sanity check that all the canonical numbers are present
|
||||
header := chain.CurrentHeader()
|
||||
for number := head.NumberU64(); number > 0; number-- {
|
||||
for number := head.Number.Uint64(); number > 0; number-- {
|
||||
if hash := chain.GetHeaderByNumber(number).Hash(); hash != header.Hash() {
|
||||
t.Fatalf("header %d: canonical hash mismatch: have %x, want %x", number, hash, header.Hash())
|
||||
}
|
||||
@@ -2150,8 +2150,8 @@ func testInsertKnownChainData(t *testing.T, typ string) {
|
||||
return err
|
||||
}
|
||||
asserter = func(t *testing.T, block *types.Block) {
|
||||
if chain.CurrentFastBlock().Hash() != block.Hash() {
|
||||
t.Fatalf("current head fast block mismatch, have %v, want %v", chain.CurrentFastBlock().Hash().Hex(), block.Hash().Hex())
|
||||
if chain.CurrentSnapBlock().Hash() != block.Hash() {
|
||||
t.Fatalf("current head fast block mismatch, have %v, want %v", chain.CurrentSnapBlock().Hash().Hex(), block.Hash().Hex())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -2324,8 +2324,8 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
|
||||
return err
|
||||
}
|
||||
asserter = func(t *testing.T, block *types.Block) {
|
||||
if chain.CurrentFastBlock().Hash() != block.Hash() {
|
||||
t.Fatalf("current head fast block mismatch, have %v, want %v", chain.CurrentFastBlock().Hash().Hex(), block.Hash().Hex())
|
||||
if chain.CurrentSnapBlock().Hash() != block.Hash() {
|
||||
t.Fatalf("current head fast block mismatch, have %v, want %v", chain.CurrentSnapBlock().Hash().Hex(), block.Hash().Hex())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -2452,7 +2452,7 @@ func TestReorgToShorterRemovesCanonMapping(t *testing.T) {
|
||||
if n, err := chain.InsertChain(canonblocks); err != nil {
|
||||
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||
}
|
||||
canonNum := chain.CurrentBlock().NumberU64()
|
||||
canonNum := chain.CurrentBlock().Number.Uint64()
|
||||
canonHash := chain.CurrentBlock().Hash()
|
||||
_, err = chain.InsertChain(sideblocks)
|
||||
if err != nil {
|
||||
@@ -2467,7 +2467,7 @@ func TestReorgToShorterRemovesCanonMapping(t *testing.T) {
|
||||
t.Errorf("expected block to be gone: %v", blockByNum.NumberU64())
|
||||
}
|
||||
if headerByNum := chain.GetHeaderByNumber(canonNum); headerByNum != nil {
|
||||
t.Errorf("expected header to be gone: %v", headerByNum.Number.Uint64())
|
||||
t.Errorf("expected header to be gone: %v", headerByNum.Number)
|
||||
}
|
||||
if blockByHash := chain.GetBlockByHash(canonHash); blockByHash == nil {
|
||||
t.Errorf("expected block to be present: %x", blockByHash.Hash())
|
||||
@@ -2553,7 +2553,7 @@ func TestTransactionIndices(t *testing.T) {
|
||||
t.Fatalf("Oldest indexded block mismatch, want %d, have %d", *tail, *stored)
|
||||
}
|
||||
if tail != nil {
|
||||
for i := *tail; i <= chain.CurrentBlock().NumberU64(); i++ {
|
||||
for i := *tail; i <= chain.CurrentBlock().Number.Uint64(); i++ {
|
||||
block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i)
|
||||
if block.Transactions().Len() == 0 {
|
||||
continue
|
||||
@@ -2649,7 +2649,7 @@ func TestSkipStaleTxIndicesInSnapSync(t *testing.T) {
|
||||
t.Fatalf("Oldest indexded block mismatch, want %d, have %d", *tail, *stored)
|
||||
}
|
||||
if tail != nil {
|
||||
for i := *tail; i <= chain.CurrentBlock().NumberU64(); i++ {
|
||||
for i := *tail; i <= chain.CurrentBlock().Number.Uint64(); i++ {
|
||||
block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i)
|
||||
if block.Transactions().Len() == 0 {
|
||||
continue
|
||||
@@ -2752,7 +2752,8 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
|
||||
b.Fatalf("failed to insert shared chain: %v", err)
|
||||
}
|
||||
b.StopTimer()
|
||||
if got := chain.CurrentBlock().Transactions().Len(); got != numTxs*numBlocks {
|
||||
block := chain.GetBlockByHash(chain.CurrentBlock().Hash())
|
||||
if got := block.Transactions().Len(); got != numTxs*numBlocks {
|
||||
b.Fatalf("Transactions were not included, expected %d, got %d", numTxs*numBlocks, got)
|
||||
}
|
||||
}
|
||||
@@ -3715,8 +3716,8 @@ func TestSetCanonical(t *testing.T) {
|
||||
if chain.CurrentBlock().Hash() != head.Hash() {
|
||||
t.Fatalf("Unexpected block hash, want %x, got %x", head.Hash(), chain.CurrentBlock().Hash())
|
||||
}
|
||||
if chain.CurrentFastBlock().Hash() != head.Hash() {
|
||||
t.Fatalf("Unexpected fast block hash, want %x, got %x", head.Hash(), chain.CurrentFastBlock().Hash())
|
||||
if chain.CurrentSnapBlock().Hash() != head.Hash() {
|
||||
t.Fatalf("Unexpected fast block hash, want %x, got %x", head.Hash(), chain.CurrentSnapBlock().Hash())
|
||||
}
|
||||
if chain.CurrentHeader().Hash() != head.Hash() {
|
||||
t.Fatalf("Unexpected head header, want %x, got %x", head.Hash(), chain.CurrentHeader().Hash())
|
||||
@@ -3799,8 +3800,8 @@ func TestCanonicalHashMarker(t *testing.T) {
|
||||
if chain.CurrentBlock().Hash() != head.Hash() {
|
||||
t.Fatalf("Unexpected block hash, want %x, got %x", head.Hash(), chain.CurrentBlock().Hash())
|
||||
}
|
||||
if chain.CurrentFastBlock().Hash() != head.Hash() {
|
||||
t.Fatalf("Unexpected fast block hash, want %x, got %x", head.Hash(), chain.CurrentFastBlock().Hash())
|
||||
if chain.CurrentSnapBlock().Hash() != head.Hash() {
|
||||
t.Fatalf("Unexpected fast block hash, want %x, got %x", head.Hash(), chain.CurrentSnapBlock().Hash())
|
||||
}
|
||||
if chain.CurrentHeader().Hash() != head.Hash() {
|
||||
t.Fatalf("Unexpected head header, want %x, got %x", head.Hash(), chain.CurrentHeader().Hash())
|
||||
|
||||
@@ -156,6 +156,11 @@ func (b *BlockGen) Number() *big.Int {
|
||||
return new(big.Int).Set(b.header.Number)
|
||||
}
|
||||
|
||||
// Timestamp returns the timestamp of the block being generated.
|
||||
func (b *BlockGen) Timestamp() uint64 {
|
||||
return b.header.Time
|
||||
}
|
||||
|
||||
// BaseFee returns the EIP-1559 base fee of the block being generated.
|
||||
func (b *BlockGen) BaseFee() *big.Int {
|
||||
return new(big.Int).Set(b.header.BaseFee)
|
||||
@@ -207,23 +212,31 @@ func (b *BlockGen) AddUncle(h *types.Header) {
|
||||
}
|
||||
|
||||
// AddWithdrawal adds a withdrawal to the generated block.
|
||||
func (b *BlockGen) AddWithdrawal(w *types.Withdrawal) {
|
||||
// The withdrawal will be assigned the next valid index.
|
||||
var idx uint64
|
||||
// It returns the withdrawal index.
|
||||
func (b *BlockGen) AddWithdrawal(w *types.Withdrawal) uint64 {
|
||||
cpy := *w
|
||||
cpy.Index = b.nextWithdrawalIndex()
|
||||
b.withdrawals = append(b.withdrawals, &cpy)
|
||||
return cpy.Index
|
||||
}
|
||||
|
||||
// nextWithdrawalIndex computes the index of the next withdrawal.
|
||||
func (b *BlockGen) nextWithdrawalIndex() uint64 {
|
||||
if len(b.withdrawals) != 0 {
|
||||
return b.withdrawals[len(b.withdrawals)-1].Index + 1
|
||||
}
|
||||
for i := b.i - 1; i >= 0; i-- {
|
||||
if wd := b.chain[i].Withdrawals(); len(wd) != 0 {
|
||||
idx = wd[len(wd)-1].Index + 1
|
||||
break
|
||||
return wd[len(wd)-1].Index + 1
|
||||
}
|
||||
if i == 0 {
|
||||
// Correctly set the index if no parent had withdrawals
|
||||
// Correctly set the index if no parent had withdrawals.
|
||||
if wd := b.parent.Withdrawals(); len(wd) != 0 {
|
||||
idx = wd[len(wd)-1].Index + 1
|
||||
return wd[len(wd)-1].Index + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
w.Index = idx
|
||||
b.withdrawals = append(b.withdrawals, w)
|
||||
return 0
|
||||
}
|
||||
|
||||
// PrevBlock returns a previously generated block by number. It panics if
|
||||
|
||||
@@ -19,7 +19,10 @@ package core
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
@@ -28,6 +31,112 @@ import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
func TestGenerateWithdrawalChain(t *testing.T) {
|
||||
var (
|
||||
keyHex = "9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c"
|
||||
key, _ = crypto.HexToECDSA(keyHex)
|
||||
address = crypto.PubkeyToAddress(key.PublicKey) // 658bdf435d810c91414ec09147daa6db62406379
|
||||
aa = common.Address{0xaa}
|
||||
bb = common.Address{0xbb}
|
||||
funds = big.NewInt(0).Mul(big.NewInt(1337), big.NewInt(params.Ether))
|
||||
config = *params.AllEthashProtocolChanges
|
||||
gspec = &Genesis{
|
||||
Config: &config,
|
||||
Alloc: GenesisAlloc{address: {Balance: funds}},
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
Difficulty: common.Big1,
|
||||
GasLimit: 5_000_000,
|
||||
}
|
||||
gendb = rawdb.NewMemoryDatabase()
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
)
|
||||
|
||||
config.TerminalTotalDifficultyPassed = true
|
||||
config.TerminalTotalDifficulty = common.Big0
|
||||
config.ShanghaiTime = u64(0)
|
||||
|
||||
// init 0xaa with some storage elements
|
||||
storage := make(map[common.Hash]common.Hash)
|
||||
storage[common.Hash{0x00}] = common.Hash{0x00}
|
||||
storage[common.Hash{0x01}] = common.Hash{0x01}
|
||||
storage[common.Hash{0x02}] = common.Hash{0x02}
|
||||
storage[common.Hash{0x03}] = common.HexToHash("0303")
|
||||
gspec.Alloc[aa] = GenesisAccount{
|
||||
Balance: common.Big1,
|
||||
Nonce: 1,
|
||||
Storage: storage,
|
||||
Code: common.Hex2Bytes("6042"),
|
||||
}
|
||||
gspec.Alloc[bb] = GenesisAccount{
|
||||
Balance: common.Big2,
|
||||
Nonce: 1,
|
||||
Storage: storage,
|
||||
Code: common.Hex2Bytes("600154600354"),
|
||||
}
|
||||
|
||||
genesis := gspec.MustCommit(gendb)
|
||||
|
||||
chain, _ := GenerateChain(gspec.Config, genesis, beacon.NewFaker(), gendb, 4, func(i int, gen *BlockGen) {
|
||||
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(address), address, big.NewInt(1000), params.TxGas, new(big.Int).Add(gen.BaseFee(), common.Big1), nil), signer, key)
|
||||
gen.AddTx(tx)
|
||||
if i == 1 {
|
||||
gen.AddWithdrawal(&types.Withdrawal{
|
||||
Validator: 42,
|
||||
Address: common.Address{0xee},
|
||||
Amount: 1337,
|
||||
})
|
||||
gen.AddWithdrawal(&types.Withdrawal{
|
||||
Validator: 13,
|
||||
Address: common.Address{0xee},
|
||||
Amount: 1,
|
||||
})
|
||||
}
|
||||
if i == 3 {
|
||||
gen.AddWithdrawal(&types.Withdrawal{
|
||||
Validator: 42,
|
||||
Address: common.Address{0xee},
|
||||
Amount: 1337,
|
||||
})
|
||||
gen.AddWithdrawal(&types.Withdrawal{
|
||||
Validator: 13,
|
||||
Address: common.Address{0xee},
|
||||
Amount: 1,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Import the chain. This runs all block validation rules.
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||
fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
|
||||
return
|
||||
}
|
||||
|
||||
// enforce that withdrawal indexes are monotonically increasing from 0
|
||||
var (
|
||||
withdrawalIndex uint64
|
||||
head = blockchain.CurrentBlock().Number.Uint64()
|
||||
)
|
||||
for i := 0; i < int(head); i++ {
|
||||
block := blockchain.GetBlockByNumber(uint64(i))
|
||||
if block == nil {
|
||||
t.Fatalf("block %d not found", i)
|
||||
}
|
||||
if len(block.Withdrawals()) == 0 {
|
||||
continue
|
||||
}
|
||||
for j := 0; j < len(block.Withdrawals()); j++ {
|
||||
if block.Withdrawals()[j].Index != withdrawalIndex {
|
||||
t.Fatalf("withdrawal index %d does not equal expected index %d", block.Withdrawals()[j].Index, withdrawalIndex)
|
||||
}
|
||||
withdrawalIndex += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleGenerateChain() {
|
||||
var (
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
@@ -88,7 +197,7 @@ func ExampleGenerateChain() {
|
||||
}
|
||||
|
||||
state, _ := blockchain.State()
|
||||
fmt.Printf("last block: #%d\n", blockchain.CurrentBlock().Number())
|
||||
fmt.Printf("last block: #%d\n", blockchain.CurrentBlock().Number)
|
||||
fmt.Println("balance of addr1:", state.GetBalance(addr1))
|
||||
fmt.Println("balance of addr2:", state.GetBalance(addr2))
|
||||
fmt.Println("balance of addr3:", state.GetBalance(addr3))
|
||||
|
||||
@@ -76,7 +76,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||
// Create a pro-fork block, and try to feed into the no-fork chain
|
||||
bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
|
||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64()))
|
||||
for j := 0; j < len(blocks)/2; j++ {
|
||||
blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
|
||||
}
|
||||
@@ -87,19 +87,19 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||
t.Fatalf("failed to commit contra-fork head for expansion: %v", err)
|
||||
}
|
||||
bc.Stop()
|
||||
blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
blocks, _ = GenerateChain(&proConf, conBc.GetBlockByHash(conBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
if _, err := conBc.InsertChain(blocks); err == nil {
|
||||
t.Fatalf("contra-fork chain accepted pro-fork block: %v", blocks[0])
|
||||
}
|
||||
// Create a proper no-fork block for the contra-forker
|
||||
blocks, _ = GenerateChain(&conConf, conBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
blocks, _ = GenerateChain(&conConf, conBc.GetBlockByHash(conBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
if _, err := conBc.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err)
|
||||
}
|
||||
// Create a no-fork block, and try to feed into the pro-fork chain
|
||||
bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
|
||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64()))
|
||||
for j := 0; j < len(blocks)/2; j++ {
|
||||
blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
|
||||
}
|
||||
@@ -110,12 +110,12 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||
t.Fatalf("failed to commit pro-fork head for expansion: %v", err)
|
||||
}
|
||||
bc.Stop()
|
||||
blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
blocks, _ = GenerateChain(&conConf, proBc.GetBlockByHash(proBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
if _, err := proBc.InsertChain(blocks); err == nil {
|
||||
t.Fatalf("pro-fork chain accepted contra-fork block: %v", blocks[0])
|
||||
}
|
||||
// Create a proper pro-fork block for the pro-forker
|
||||
blocks, _ = GenerateChain(&proConf, proBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
blocks, _ = GenerateChain(&proConf, proBc.GetBlockByHash(proBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
if _, err := proBc.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("pro-fork chain didn't accepted pro-fork block: %v", err)
|
||||
}
|
||||
@@ -124,7 +124,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||
bc, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, congspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
defer bc.Stop()
|
||||
|
||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64()))
|
||||
for j := 0; j < len(blocks)/2; j++ {
|
||||
blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
|
||||
}
|
||||
@@ -134,7 +134,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||
if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil {
|
||||
t.Fatalf("failed to commit contra-fork head for expansion: %v", err)
|
||||
}
|
||||
blocks, _ = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
blocks, _ = GenerateChain(&proConf, conBc.GetBlockByHash(conBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
if _, err := conBc.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err)
|
||||
}
|
||||
@@ -142,7 +142,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||
bc, _ = NewBlockChain(rawdb.NewMemoryDatabase(), nil, progspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
defer bc.Stop()
|
||||
|
||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64()))
|
||||
for j := 0; j < len(blocks)/2; j++ {
|
||||
blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
|
||||
}
|
||||
@@ -152,7 +152,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||
if err := bc.stateCache.TrieDB().Commit(bc.CurrentHeader().Root, false); err != nil {
|
||||
t.Fatalf("failed to commit pro-fork head for expansion: %v", err)
|
||||
}
|
||||
blocks, _ = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
blocks, _ = GenerateChain(&conConf, proBc.GetBlockByHash(proBc.CurrentBlock().Hash()), ethash.NewFaker(), genDb, 1, func(i int, gen *BlockGen) {})
|
||||
if _, err := proBc.InsertChain(blocks); err != nil {
|
||||
t.Fatalf("pro-fork chain didn't accept contra-fork block post-fork: %v", err)
|
||||
}
|
||||
|
||||
@@ -70,10 +70,10 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
|
||||
}
|
||||
|
||||
// NewEVMTxContext creates a new transaction context for a single transaction.
|
||||
func NewEVMTxContext(msg Message) vm.TxContext {
|
||||
func NewEVMTxContext(msg *Message) vm.TxContext {
|
||||
return vm.TxContext{
|
||||
Origin: msg.From(),
|
||||
GasPrice: new(big.Int).Set(msg.GasPrice()),
|
||||
Origin: msg.From,
|
||||
GasPrice: new(big.Int).Set(msg.GasPrice),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -107,14 +107,16 @@ func TestCreation(t *testing.T) {
|
||||
params.GoerliChainConfig,
|
||||
params.GoerliGenesisHash,
|
||||
[]testcase{
|
||||
{0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
|
||||
{1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block
|
||||
{1561651, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // First Istanbul block
|
||||
{4460643, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // Last Istanbul block
|
||||
{4460644, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // First Berlin block
|
||||
{5000000, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block
|
||||
{5062605, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 0}}, // First London block
|
||||
{6000000, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 0}}, // Future London block
|
||||
{0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
|
||||
{1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block
|
||||
{1561651, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // First Istanbul block
|
||||
{4460643, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // Last Istanbul block
|
||||
{4460644, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // First Berlin block
|
||||
{5000000, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block
|
||||
{5062605, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // First London block
|
||||
{6000000, 1678832735, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // Last London block
|
||||
{6000001, 1678832736, ID{Hash: checksumToBytes(0xf9843abf), Next: 0}}, // First Shanghai block
|
||||
{6500000, 2678832736, ID{Hash: checksumToBytes(0xf9843abf), Next: 0}}, // Future Shanghai block
|
||||
},
|
||||
},
|
||||
// Sepolia test cases
|
||||
@@ -306,7 +308,7 @@ func TestValidation(t *testing.T) {
|
||||
|
||||
// Local is mainnet Gray Glacier, and isn't aware of more forks. Remote announces Gray Glacier +
|
||||
// 0xffffffff. Local needs software update, reject.
|
||||
{×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(checksumUpdate(0xf0afd0e3, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale},
|
||||
{params.MainnetChainConfig, 15050000, 0, ID{Hash: checksumToBytes(checksumUpdate(0xf0afd0e3, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale},
|
||||
|
||||
// Local is mainnet Gray Glacier, and is aware of Shanghai. Remote announces Shanghai +
|
||||
// 0xffffffff. Local needs software update, reject.
|
||||
|
||||
@@ -49,6 +49,11 @@ func (gp *GasPool) Gas() uint64 {
|
||||
return uint64(*gp)
|
||||
}
|
||||
|
||||
// SetGas sets the amount of gas with the provided number.
|
||||
func (gp *GasPool) SetGas(gas uint64) {
|
||||
*(*uint64)(gp) = gas
|
||||
}
|
||||
|
||||
func (gp *GasPool) String() string {
|
||||
return fmt.Sprintf("%d", *gp)
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ func (ga *GenesisAlloc) deriveHash() (common.Hash, error) {
|
||||
// flush is very similar with deriveHash, but the main difference is
|
||||
// all the generated states will be persisted into the given database.
|
||||
// Also, the genesis state specification will be flushed as well.
|
||||
func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database) error {
|
||||
func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error {
|
||||
statedb, err := state.New(common.Hash{}, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -166,15 +166,15 @@ func (ga *GenesisAlloc) flush(db ethdb.Database, triedb *trie.Database) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rawdb.WriteGenesisStateSpec(db, root, blob)
|
||||
rawdb.WriteGenesisStateSpec(db, blockhash, blob)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CommitGenesisState loads the stored genesis state with the given block
|
||||
// hash and commits it into the provided trie database.
|
||||
func CommitGenesisState(db ethdb.Database, triedb *trie.Database, hash common.Hash) error {
|
||||
func CommitGenesisState(db ethdb.Database, triedb *trie.Database, blockhash common.Hash) error {
|
||||
var alloc GenesisAlloc
|
||||
blob := rawdb.ReadGenesisStateSpec(db, hash)
|
||||
blob := rawdb.ReadGenesisStateSpec(db, blockhash)
|
||||
if len(blob) != 0 {
|
||||
if err := alloc.UnmarshalJSON(blob); err != nil {
|
||||
return err
|
||||
@@ -186,7 +186,7 @@ func CommitGenesisState(db ethdb.Database, triedb *trie.Database, hash common.Ha
|
||||
// - supported networks(mainnet, testnets), recover with defined allocations
|
||||
// - private network, can't recover
|
||||
var genesis *Genesis
|
||||
switch hash {
|
||||
switch blockhash {
|
||||
case params.MainnetGenesisHash:
|
||||
genesis = DefaultGenesisBlock()
|
||||
case params.RinkebyGenesisHash:
|
||||
@@ -202,7 +202,7 @@ func CommitGenesisState(db ethdb.Database, triedb *trie.Database, hash common.Ha
|
||||
return errors.New("not found")
|
||||
}
|
||||
}
|
||||
return alloc.flush(db, triedb)
|
||||
return alloc.flush(db, triedb, blockhash)
|
||||
}
|
||||
|
||||
// GenesisAccount is an account in the state of the genesis block.
|
||||
@@ -467,7 +467,7 @@ func (g *Genesis) ToBlock() *types.Block {
|
||||
}
|
||||
var withdrawals []*types.Withdrawal
|
||||
if g.Config != nil && g.Config.IsShanghai(g.Timestamp) {
|
||||
head.WithdrawalsHash = &types.EmptyRootHash
|
||||
head.WithdrawalsHash = &types.EmptyWithdrawalsHash
|
||||
withdrawals = make([]*types.Withdrawal, 0)
|
||||
}
|
||||
return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)).WithWithdrawals(withdrawals)
|
||||
@@ -493,7 +493,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *trie.Database) (*types.Block
|
||||
// All the checks has passed, flush the states derived from the genesis
|
||||
// specification as well as the specification itself into the provided
|
||||
// database.
|
||||
if err := g.Alloc.flush(db, triedb); err != nil {
|
||||
if err := g.Alloc.flush(db, triedb, block.Hash()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty())
|
||||
|
||||
@@ -389,7 +389,7 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, start time.Time,
|
||||
if res.ignored > 0 {
|
||||
context = append(context, []interface{}{"ignored", res.ignored}...)
|
||||
}
|
||||
log.Info("Imported new block headers", context...)
|
||||
log.Debug("Imported new block headers", context...)
|
||||
return res.status, err
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ import (
|
||||
func ReadCanonicalHash(db ethdb.Reader, number uint64) common.Hash {
|
||||
var data []byte
|
||||
db.ReadAncients(func(reader ethdb.AncientReaderOp) error {
|
||||
data, _ = reader.Ancient(chainFreezerHashTable, number)
|
||||
data, _ = reader.Ancient(ChainFreezerHashTable, number)
|
||||
if len(data) == 0 {
|
||||
// Get it by hash from leveldb
|
||||
data, _ = db.Get(headerHashKey(number))
|
||||
@@ -334,7 +334,7 @@ func ReadHeaderRange(db ethdb.Reader, number uint64, count uint64) []rlp.RawValu
|
||||
}
|
||||
// read remaining from ancients
|
||||
max := count * 700
|
||||
data, err := db.AncientRange(chainFreezerHeaderTable, i+1-count, count, max)
|
||||
data, err := db.AncientRange(ChainFreezerHeaderTable, i+1-count, count, max)
|
||||
if err == nil && uint64(len(data)) == count {
|
||||
// the data is on the order [h, h+1, .., n] -- reordering needed
|
||||
for i := range data {
|
||||
@@ -351,7 +351,7 @@ func ReadHeaderRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValu
|
||||
// First try to look up the data in ancient database. Extra hash
|
||||
// comparison is necessary since ancient database only maintains
|
||||
// the canonical data.
|
||||
data, _ = reader.Ancient(chainFreezerHeaderTable, number)
|
||||
data, _ = reader.Ancient(ChainFreezerHeaderTable, number)
|
||||
if len(data) > 0 && crypto.Keccak256Hash(data) == hash {
|
||||
return nil
|
||||
}
|
||||
@@ -427,7 +427,7 @@ func deleteHeaderWithoutNumber(db ethdb.KeyValueWriter, hash common.Hash, number
|
||||
// isCanon is an internal utility method, to check whether the given number/hash
|
||||
// is part of the ancient (canon) set.
|
||||
func isCanon(reader ethdb.AncientReaderOp, number uint64, hash common.Hash) bool {
|
||||
h, err := reader.Ancient(chainFreezerHashTable, number)
|
||||
h, err := reader.Ancient(ChainFreezerHashTable, number)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -443,7 +443,7 @@ func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue
|
||||
db.ReadAncients(func(reader ethdb.AncientReaderOp) error {
|
||||
// Check if the data is in ancients
|
||||
if isCanon(reader, number, hash) {
|
||||
data, _ = reader.Ancient(chainFreezerBodiesTable, number)
|
||||
data, _ = reader.Ancient(ChainFreezerBodiesTable, number)
|
||||
return nil
|
||||
}
|
||||
// If not, try reading from leveldb
|
||||
@@ -458,7 +458,7 @@ func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue
|
||||
func ReadCanonicalBodyRLP(db ethdb.Reader, number uint64) rlp.RawValue {
|
||||
var data []byte
|
||||
db.ReadAncients(func(reader ethdb.AncientReaderOp) error {
|
||||
data, _ = reader.Ancient(chainFreezerBodiesTable, number)
|
||||
data, _ = reader.Ancient(ChainFreezerBodiesTable, number)
|
||||
if len(data) > 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -526,7 +526,7 @@ func ReadTdRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
|
||||
db.ReadAncients(func(reader ethdb.AncientReaderOp) error {
|
||||
// Check if the data is in ancients
|
||||
if isCanon(reader, number, hash) {
|
||||
data, _ = reader.Ancient(chainFreezerDifficultyTable, number)
|
||||
data, _ = reader.Ancient(ChainFreezerDifficultyTable, number)
|
||||
return nil
|
||||
}
|
||||
// If not, try reading from leveldb
|
||||
@@ -586,7 +586,7 @@ func ReadReceiptsRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawVa
|
||||
db.ReadAncients(func(reader ethdb.AncientReaderOp) error {
|
||||
// Check if the data is in ancients
|
||||
if isCanon(reader, number, hash) {
|
||||
data, _ = reader.Ancient(chainFreezerReceiptTable, number)
|
||||
data, _ = reader.Ancient(ChainFreezerReceiptTable, number)
|
||||
return nil
|
||||
}
|
||||
// If not, try reading from leveldb
|
||||
@@ -636,7 +636,14 @@ func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, config *para
|
||||
log.Error("Missing body but have receipt", "hash", hash, "number", number)
|
||||
return nil
|
||||
}
|
||||
if err := receipts.DeriveFields(config, hash, number, body.Transactions); err != nil {
|
||||
header := ReadHeader(db, hash, number)
|
||||
var baseFee *big.Int
|
||||
if header == nil {
|
||||
baseFee = big.NewInt(0)
|
||||
} else {
|
||||
baseFee = header.BaseFee
|
||||
}
|
||||
if err := receipts.DeriveFields(config, hash, number, baseFee, body.Transactions); err != nil {
|
||||
log.Error("Failed to derive block receipts fields", "hash", hash, "number", number, "err", err)
|
||||
return nil
|
||||
}
|
||||
@@ -787,19 +794,19 @@ func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts
|
||||
|
||||
func writeAncientBlock(op ethdb.AncientWriteOp, block *types.Block, header *types.Header, receipts []*types.ReceiptForStorage, td *big.Int) error {
|
||||
num := block.NumberU64()
|
||||
if err := op.AppendRaw(chainFreezerHashTable, num, block.Hash().Bytes()); err != nil {
|
||||
if err := op.AppendRaw(ChainFreezerHashTable, num, block.Hash().Bytes()); err != nil {
|
||||
return fmt.Errorf("can't add block %d hash: %v", num, err)
|
||||
}
|
||||
if err := op.Append(chainFreezerHeaderTable, num, header); err != nil {
|
||||
if err := op.Append(ChainFreezerHeaderTable, num, header); err != nil {
|
||||
return fmt.Errorf("can't append block header %d: %v", num, err)
|
||||
}
|
||||
if err := op.Append(chainFreezerBodiesTable, num, block.Body()); err != nil {
|
||||
if err := op.Append(ChainFreezerBodiesTable, num, block.Body()); err != nil {
|
||||
return fmt.Errorf("can't append block body %d: %v", num, err)
|
||||
}
|
||||
if err := op.Append(chainFreezerReceiptTable, num, receipts); err != nil {
|
||||
if err := op.Append(ChainFreezerReceiptTable, num, receipts); err != nil {
|
||||
return fmt.Errorf("can't append block %d receipts: %v", num, err)
|
||||
}
|
||||
if err := op.Append(chainFreezerDifficultyTable, num, td); err != nil {
|
||||
if err := op.Append(ChainFreezerDifficultyTable, num, td); err != nil {
|
||||
return fmt.Errorf("can't append block %d total difficulty: %v", num, err)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -113,8 +113,8 @@ func TestBlockStorage(t *testing.T) {
|
||||
block := types.NewBlockWithHeader(&types.Header{
|
||||
Extra: []byte("test block"),
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
TxHash: types.EmptyRootHash,
|
||||
ReceiptHash: types.EmptyRootHash,
|
||||
TxHash: types.EmptyTxsHash,
|
||||
ReceiptHash: types.EmptyReceiptsHash,
|
||||
})
|
||||
if entry := ReadBlock(db, block.Hash(), block.NumberU64()); entry != nil {
|
||||
t.Fatalf("Non existent block returned: %v", entry)
|
||||
@@ -161,8 +161,8 @@ func TestPartialBlockStorage(t *testing.T) {
|
||||
block := types.NewBlockWithHeader(&types.Header{
|
||||
Extra: []byte("test block"),
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
TxHash: types.EmptyRootHash,
|
||||
ReceiptHash: types.EmptyRootHash,
|
||||
TxHash: types.EmptyTxsHash,
|
||||
ReceiptHash: types.EmptyReceiptsHash,
|
||||
})
|
||||
// Store a header and check that it's not recognized as a block
|
||||
WriteHeader(db, block.Header())
|
||||
@@ -198,8 +198,8 @@ func TestBadBlockStorage(t *testing.T) {
|
||||
Number: big.NewInt(1),
|
||||
Extra: []byte("bad block"),
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
TxHash: types.EmptyRootHash,
|
||||
ReceiptHash: types.EmptyRootHash,
|
||||
TxHash: types.EmptyTxsHash,
|
||||
ReceiptHash: types.EmptyReceiptsHash,
|
||||
})
|
||||
if entry := ReadBadBlock(db, block.Hash()); entry != nil {
|
||||
t.Fatalf("Non existent block returned: %v", entry)
|
||||
@@ -216,8 +216,8 @@ func TestBadBlockStorage(t *testing.T) {
|
||||
Number: big.NewInt(2),
|
||||
Extra: []byte("bad block two"),
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
TxHash: types.EmptyRootHash,
|
||||
ReceiptHash: types.EmptyRootHash,
|
||||
TxHash: types.EmptyTxsHash,
|
||||
ReceiptHash: types.EmptyReceiptsHash,
|
||||
})
|
||||
WriteBadBlock(db, blockTwo)
|
||||
|
||||
@@ -235,8 +235,8 @@ func TestBadBlockStorage(t *testing.T) {
|
||||
Number: big.NewInt(int64(n)),
|
||||
Extra: []byte("bad block"),
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
TxHash: types.EmptyRootHash,
|
||||
ReceiptHash: types.EmptyRootHash,
|
||||
TxHash: types.EmptyTxsHash,
|
||||
ReceiptHash: types.EmptyReceiptsHash,
|
||||
})
|
||||
WriteBadBlock(db, block)
|
||||
}
|
||||
@@ -446,8 +446,8 @@ func TestAncientStorage(t *testing.T) {
|
||||
Number: big.NewInt(0),
|
||||
Extra: []byte("test block"),
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
TxHash: types.EmptyRootHash,
|
||||
ReceiptHash: types.EmptyRootHash,
|
||||
TxHash: types.EmptyTxsHash,
|
||||
ReceiptHash: types.EmptyReceiptsHash,
|
||||
})
|
||||
// Ensure nothing non-existent will be read
|
||||
hash, number := block.Hash(), block.NumberU64()
|
||||
@@ -889,8 +889,8 @@ func TestHeadersRLPStorage(t *testing.T) {
|
||||
Number: big.NewInt(int64(i)),
|
||||
Extra: []byte("test block"),
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
TxHash: types.EmptyRootHash,
|
||||
ReceiptHash: types.EmptyRootHash,
|
||||
TxHash: types.EmptyTxsHash,
|
||||
ReceiptHash: types.EmptyReceiptsHash,
|
||||
ParentHash: pHash,
|
||||
})
|
||||
chain = append(chain, block)
|
||||
|
||||
@@ -82,15 +82,15 @@ func WriteChainConfig(db ethdb.KeyValueWriter, hash common.Hash, cfg *params.Cha
|
||||
}
|
||||
|
||||
// ReadGenesisStateSpec retrieves the genesis state specification based on the
|
||||
// given genesis hash.
|
||||
func ReadGenesisStateSpec(db ethdb.KeyValueReader, hash common.Hash) []byte {
|
||||
data, _ := db.Get(genesisStateSpecKey(hash))
|
||||
// given genesis (block-)hash.
|
||||
func ReadGenesisStateSpec(db ethdb.KeyValueReader, blockhash common.Hash) []byte {
|
||||
data, _ := db.Get(genesisStateSpecKey(blockhash))
|
||||
return data
|
||||
}
|
||||
|
||||
// WriteGenesisStateSpec writes the genesis state specification into the disk.
|
||||
func WriteGenesisStateSpec(db ethdb.KeyValueWriter, hash common.Hash, data []byte) {
|
||||
if err := db.Put(genesisStateSpecKey(hash), data); err != nil {
|
||||
func WriteGenesisStateSpec(db ethdb.KeyValueWriter, blockhash common.Hash, data []byte) {
|
||||
if err := db.Put(genesisStateSpecKey(blockhash), data); err != nil {
|
||||
log.Crit("Failed to store genesis state", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,30 +18,30 @@ package rawdb
|
||||
|
||||
// The list of table names of chain freezer.
|
||||
const (
|
||||
// chainFreezerHeaderTable indicates the name of the freezer header table.
|
||||
chainFreezerHeaderTable = "headers"
|
||||
// ChainFreezerHeaderTable indicates the name of the freezer header table.
|
||||
ChainFreezerHeaderTable = "headers"
|
||||
|
||||
// chainFreezerHashTable indicates the name of the freezer canonical hash table.
|
||||
chainFreezerHashTable = "hashes"
|
||||
// ChainFreezerHashTable indicates the name of the freezer canonical hash table.
|
||||
ChainFreezerHashTable = "hashes"
|
||||
|
||||
// chainFreezerBodiesTable indicates the name of the freezer block body table.
|
||||
chainFreezerBodiesTable = "bodies"
|
||||
// ChainFreezerBodiesTable indicates the name of the freezer block body table.
|
||||
ChainFreezerBodiesTable = "bodies"
|
||||
|
||||
// chainFreezerReceiptTable indicates the name of the freezer receipts table.
|
||||
chainFreezerReceiptTable = "receipts"
|
||||
// ChainFreezerReceiptTable indicates the name of the freezer receipts table.
|
||||
ChainFreezerReceiptTable = "receipts"
|
||||
|
||||
// chainFreezerDifficultyTable indicates the name of the freezer total difficulty table.
|
||||
chainFreezerDifficultyTable = "diffs"
|
||||
// ChainFreezerDifficultyTable indicates the name of the freezer total difficulty table.
|
||||
ChainFreezerDifficultyTable = "diffs"
|
||||
)
|
||||
|
||||
// chainFreezerNoSnappy configures whether compression is disabled for the ancient-tables.
|
||||
// Hashes and difficulties don't compress well.
|
||||
var chainFreezerNoSnappy = map[string]bool{
|
||||
chainFreezerHeaderTable: false,
|
||||
chainFreezerHashTable: true,
|
||||
chainFreezerBodiesTable: false,
|
||||
chainFreezerReceiptTable: false,
|
||||
chainFreezerDifficultyTable: true,
|
||||
ChainFreezerHeaderTable: false,
|
||||
ChainFreezerHashTable: true,
|
||||
ChainFreezerBodiesTable: false,
|
||||
ChainFreezerReceiptTable: false,
|
||||
ChainFreezerDifficultyTable: true,
|
||||
}
|
||||
|
||||
// The list of identifiers of ancient stores.
|
||||
|
||||
@@ -55,8 +55,8 @@ type chainFreezer struct {
|
||||
}
|
||||
|
||||
// newChainFreezer initializes the freezer for ancient chain data.
|
||||
func newChainFreezer(datadir string, namespace string, readonly bool, maxTableSize uint32, tables map[string]bool) (*chainFreezer, error) {
|
||||
freezer, err := NewFreezer(datadir, namespace, readonly, maxTableSize, tables)
|
||||
func newChainFreezer(datadir string, namespace string, readonly bool) (*chainFreezer, error) {
|
||||
freezer, err := NewChainFreezer(datadir, namespace, readonly)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -280,19 +280,19 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash
|
||||
}
|
||||
|
||||
// Write to the batch.
|
||||
if err := op.AppendRaw(chainFreezerHashTable, number, hash[:]); err != nil {
|
||||
if err := op.AppendRaw(ChainFreezerHashTable, number, hash[:]); err != nil {
|
||||
return fmt.Errorf("can't write hash to Freezer: %v", err)
|
||||
}
|
||||
if err := op.AppendRaw(chainFreezerHeaderTable, number, header); err != nil {
|
||||
if err := op.AppendRaw(ChainFreezerHeaderTable, number, header); err != nil {
|
||||
return fmt.Errorf("can't write header to Freezer: %v", err)
|
||||
}
|
||||
if err := op.AppendRaw(chainFreezerBodiesTable, number, body); err != nil {
|
||||
if err := op.AppendRaw(ChainFreezerBodiesTable, number, body); err != nil {
|
||||
return fmt.Errorf("can't write body to Freezer: %v", err)
|
||||
}
|
||||
if err := op.AppendRaw(chainFreezerReceiptTable, number, receipts); err != nil {
|
||||
if err := op.AppendRaw(ChainFreezerReceiptTable, number, receipts); err != nil {
|
||||
return fmt.Errorf("can't write receipts to Freezer: %v", err)
|
||||
}
|
||||
if err := op.AppendRaw(chainFreezerDifficultyTable, number, td); err != nil {
|
||||
if err := op.AppendRaw(ChainFreezerDifficultyTable, number, td); err != nil {
|
||||
return fmt.Errorf("can't write td to Freezer: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ func InitDatabaseFromFreezer(db ethdb.Database) {
|
||||
if i+count > frozen {
|
||||
count = frozen - i
|
||||
}
|
||||
data, err := db.AncientRange(chainFreezerHashTable, i, count, 32*count)
|
||||
data, err := db.AncientRange(ChainFreezerHashTable, i, count, 32*count)
|
||||
if err != nil {
|
||||
log.Crit("Failed to init database from freezer", "err", err)
|
||||
}
|
||||
|
||||
@@ -200,8 +200,9 @@ func resolveChainFreezerDir(ancient string) string {
|
||||
// where the chain freezer can be opened.
|
||||
func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace string, readonly bool) (ethdb.Database, error) {
|
||||
// Create the idle freezer instance
|
||||
frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly, freezerTableSize, chainFreezerNoSnappy)
|
||||
frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly)
|
||||
if err != nil {
|
||||
printChainMetadata(db)
|
||||
return nil, err
|
||||
}
|
||||
// Since the freezer can be stored separately from the user's key-value database,
|
||||
@@ -231,10 +232,12 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||
// If the freezer already contains something, ensure that the genesis blocks
|
||||
// match, otherwise we might mix up freezers across chains and destroy both
|
||||
// the freezer and the key-value store.
|
||||
frgenesis, err := frdb.Ancient(chainFreezerHashTable, 0)
|
||||
frgenesis, err := frdb.Ancient(ChainFreezerHashTable, 0)
|
||||
if err != nil {
|
||||
printChainMetadata(db)
|
||||
return nil, fmt.Errorf("failed to retrieve genesis from ancient %v", err)
|
||||
} else if !bytes.Equal(kvgenesis, frgenesis) {
|
||||
printChainMetadata(db)
|
||||
return nil, fmt.Errorf("genesis mismatch: %#x (leveldb) != %#x (ancients)", kvgenesis, frgenesis)
|
||||
}
|
||||
// Key-value store and freezer belong to the same network. Ensure that they
|
||||
@@ -242,8 +245,19 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||
if kvhash, _ := db.Get(headerHashKey(frozen)); len(kvhash) == 0 {
|
||||
// Subsequent header after the freezer limit is missing from the database.
|
||||
// Reject startup if the database has a more recent head.
|
||||
if ldbNum := *ReadHeaderNumber(db, ReadHeadHeaderHash(db)); ldbNum > frozen-1 {
|
||||
return nil, fmt.Errorf("gap in the chain between ancients (#%d) and leveldb (#%d) ", frozen, ldbNum)
|
||||
if head := *ReadHeaderNumber(db, ReadHeadHeaderHash(db)); head > frozen-1 {
|
||||
// Find the smallest block stored in the key-value store
|
||||
// in range of [frozen, head]
|
||||
var number uint64
|
||||
for number = frozen; number <= head; number++ {
|
||||
if present, _ := db.Has(headerHashKey(number)); present {
|
||||
break
|
||||
}
|
||||
}
|
||||
// We are about to exit on error. Print database metdata beore exiting
|
||||
printChainMetadata(db)
|
||||
return nil, fmt.Errorf("gap in the chain between ancients [0 - #%d] and leveldb [#%d - #%d] ",
|
||||
frozen-1, number, head)
|
||||
}
|
||||
// Database contains only older data than the freezer, this happens if the
|
||||
// state was wiped and reinited from an existing freezer.
|
||||
@@ -260,6 +274,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||
// Key-value store contains more data than the genesis block, make sure we
|
||||
// didn't freeze anything yet.
|
||||
if kvblob, _ := db.Get(headerHashKey(1)); len(kvblob) == 0 {
|
||||
printChainMetadata(db)
|
||||
return nil, errors.New("ancient chain segments already extracted, please set --datadir.ancient to the correct path")
|
||||
}
|
||||
// Block #1 is still in the database, we're allowed to init a new freezer
|
||||
@@ -581,3 +596,42 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// printChainMetadata prints out chain metadata to stderr.
|
||||
func printChainMetadata(db ethdb.KeyValueStore) {
|
||||
fmt.Fprintf(os.Stderr, "Chain metadata\n")
|
||||
for _, v := range ReadChainMetadata(db) {
|
||||
fmt.Fprintf(os.Stderr, " %s\n", strings.Join(v, ": "))
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "\n\n")
|
||||
}
|
||||
|
||||
// ReadChainMetadata returns a set of key/value pairs that contains informatin
|
||||
// about the database chain status. This can be used for diagnostic purposes
|
||||
// when investigating the state of the node.
|
||||
func ReadChainMetadata(db ethdb.KeyValueStore) [][]string {
|
||||
pp := func(val *uint64) string {
|
||||
if val == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return fmt.Sprintf("%d (%#x)", *val, *val)
|
||||
}
|
||||
data := [][]string{
|
||||
{"databaseVersion", pp(ReadDatabaseVersion(db))},
|
||||
{"headBlockHash", fmt.Sprintf("%v", ReadHeadBlockHash(db))},
|
||||
{"headFastBlockHash", fmt.Sprintf("%v", ReadHeadFastBlockHash(db))},
|
||||
{"headHeaderHash", fmt.Sprintf("%v", ReadHeadHeaderHash(db))},
|
||||
{"lastPivotNumber", pp(ReadLastPivotNumber(db))},
|
||||
{"len(snapshotSyncStatus)", fmt.Sprintf("%d bytes", len(ReadSnapshotSyncStatus(db)))},
|
||||
{"snapshotDisabled", fmt.Sprintf("%v", ReadSnapshotDisabled(db))},
|
||||
{"snapshotJournal", fmt.Sprintf("%d bytes", len(ReadSnapshotJournal(db)))},
|
||||
{"snapshotRecoveryNumber", pp(ReadSnapshotRecoveryNumber(db))},
|
||||
{"snapshotRoot", fmt.Sprintf("%v", ReadSnapshotRoot(db))},
|
||||
{"txIndexTail", pp(ReadTxIndexTail(db))},
|
||||
{"fastTxLookupLimit", pp(ReadFastTxLookupLimit(db))},
|
||||
}
|
||||
if b := ReadSkeletonSyncStatus(db); b != nil {
|
||||
data = append(data, []string{"SkeletonSyncStatus", string(b)})
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// 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/>
|
||||
|
||||
//go:build arm64 || amd64
|
||||
//go:build (arm64 || amd64) && !openbsd
|
||||
|
||||
package rawdb
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// 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/>.
|
||||
|
||||
//go:build !(arm64 || amd64)
|
||||
//go:build !((arm64 || amd64) && !openbsd)
|
||||
|
||||
package rawdb
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/prometheus/tsdb/fileutil"
|
||||
"github.com/gofrs/flock"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -75,10 +75,16 @@ type Freezer struct {
|
||||
|
||||
readonly bool
|
||||
tables map[string]*freezerTable // Data tables for storing everything
|
||||
instanceLock fileutil.Releaser // File-system lock to prevent double opens
|
||||
instanceLock *flock.Flock // File-system lock to prevent double opens
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
// NewChainFreezer is a small utility method around NewFreezer that sets the
|
||||
// default parameters for the chain storage.
|
||||
func NewChainFreezer(datadir string, namespace string, readonly bool) (*Freezer, error) {
|
||||
return NewFreezer(datadir, namespace, readonly, freezerTableSize, chainFreezerNoSnappy)
|
||||
}
|
||||
|
||||
// NewFreezer creates a freezer instance for maintaining immutable ordered
|
||||
// data according to the given parameters.
|
||||
//
|
||||
@@ -98,11 +104,17 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui
|
||||
return nil, errSymlinkDatadir
|
||||
}
|
||||
}
|
||||
flockFile := filepath.Join(datadir, "FLOCK")
|
||||
if err := os.MkdirAll(filepath.Dir(flockFile), 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Leveldb uses LOCK as the filelock filename. To prevent the
|
||||
// name collision, we use FLOCK as the lock name.
|
||||
lock, _, err := fileutil.Flock(filepath.Join(datadir, "FLOCK"))
|
||||
if err != nil {
|
||||
lock := flock.New(flockFile)
|
||||
if locked, err := lock.TryLock(); err != nil {
|
||||
return nil, err
|
||||
} else if !locked {
|
||||
return nil, errors.New("locking failed")
|
||||
}
|
||||
// Open all the supported data tables
|
||||
freezer := &Freezer{
|
||||
@@ -118,12 +130,12 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui
|
||||
for _, table := range freezer.tables {
|
||||
table.Close()
|
||||
}
|
||||
lock.Release()
|
||||
lock.Unlock()
|
||||
return nil, err
|
||||
}
|
||||
freezer.tables[name] = table
|
||||
}
|
||||
|
||||
var err error
|
||||
if freezer.readonly {
|
||||
// In readonly mode only validate, don't truncate.
|
||||
// validate also sets `freezer.frozen`.
|
||||
@@ -136,7 +148,7 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui
|
||||
for _, table := range freezer.tables {
|
||||
table.Close()
|
||||
}
|
||||
lock.Release()
|
||||
lock.Unlock()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -159,7 +171,7 @@ func (f *Freezer) Close() error {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if err := f.instanceLock.Release(); err != nil {
|
||||
if err := f.instanceLock.Unlock(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -117,7 +117,7 @@ func (it *NodeIterator) step() error {
|
||||
if !it.dataIt.Next(true) {
|
||||
it.dataIt = nil
|
||||
}
|
||||
if !bytes.Equal(account.CodeHash, emptyCodeHash) {
|
||||
if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) {
|
||||
it.codeHash = common.BytesToHash(account.CodeHash)
|
||||
addrHash := common.BytesToHash(it.stateIt.LeafKey())
|
||||
it.code, err = it.state.db.ContractCode(addrHash, common.BytesToHash(account.CodeHash))
|
||||
|
||||
@@ -31,7 +31,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -55,14 +54,6 @@ const (
|
||||
rangeCompactionThreshold = 100000
|
||||
)
|
||||
|
||||
var (
|
||||
// emptyRoot is the known root hash of an empty trie.
|
||||
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
|
||||
// emptyCode is the known hash of the empty EVM bytecode.
|
||||
emptyCode = crypto.Keccak256(nil)
|
||||
)
|
||||
|
||||
// Config includes all the configurations for pruning.
|
||||
type Config struct {
|
||||
Datadir string // The directory of the state database
|
||||
@@ -446,7 +437,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
|
||||
if err := rlp.DecodeBytes(accIter.LeafBlob(), &acc); err != nil {
|
||||
return err
|
||||
}
|
||||
if acc.Root != emptyRoot {
|
||||
if acc.Root != types.EmptyRootHash {
|
||||
id := trie.StorageTrieID(genesis.Root(), common.BytesToHash(accIter.LeafKey()), acc.Root)
|
||||
storageTrie, err := trie.NewStateTrie(id, trie.NewDatabase(db))
|
||||
if err != nil {
|
||||
@@ -463,7 +454,7 @@ func extractGenesis(db ethdb.Database, stateBloom *stateBloom) error {
|
||||
return storageIter.Error()
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(acc.CodeHash, emptyCode) {
|
||||
if !bytes.Equal(acc.CodeHash, types.EmptyCodeHash.Bytes()) {
|
||||
stateBloom.Put(acc.CodeHash, nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
@@ -41,10 +42,10 @@ func SlimAccount(nonce uint64, balance *big.Int, root common.Hash, codehash []by
|
||||
Nonce: nonce,
|
||||
Balance: balance,
|
||||
}
|
||||
if root != emptyRoot {
|
||||
if root != types.EmptyRootHash {
|
||||
slim.Root = root[:]
|
||||
}
|
||||
if !bytes.Equal(codehash, emptyCode[:]) {
|
||||
if !bytes.Equal(codehash, types.EmptyCodeHash[:]) {
|
||||
slim.CodeHash = codehash
|
||||
}
|
||||
return slim
|
||||
@@ -68,10 +69,10 @@ func FullAccount(data []byte) (Account, error) {
|
||||
return Account{}, err
|
||||
}
|
||||
if len(account.Root) == 0 {
|
||||
account.Root = emptyRoot[:]
|
||||
account.Root = types.EmptyRootHash[:]
|
||||
}
|
||||
if len(account.CodeHash) == 0 {
|
||||
account.CodeHash = emptyCode[:]
|
||||
account.CodeHash = types.EmptyCodeHash[:]
|
||||
}
|
||||
return account, nil
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -74,7 +75,7 @@ func GenerateTrie(snaptree *Tree, root common.Hash, src ethdb.Database, dst ethd
|
||||
scheme := snaptree.triedb.Scheme()
|
||||
got, err := generateTrieRoot(dst, scheme, acctIt, common.Hash{}, stackTrieGenerate, func(dst ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) {
|
||||
// Migrate the code first, commit the contract code into the tmp db.
|
||||
if codeHash != emptyCode {
|
||||
if codeHash != types.EmptyCodeHash {
|
||||
code := rawdb.ReadCode(src, codeHash)
|
||||
if len(code) == 0 {
|
||||
return common.Hash{}, errors.New("failed to read contract code")
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -35,12 +35,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// emptyRoot is the known root hash of an empty trie.
|
||||
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
|
||||
// emptyCode is the known hash of the empty EVM bytecode.
|
||||
emptyCode = crypto.Keccak256Hash(nil)
|
||||
|
||||
// accountCheckRange is the upper limit of the number of accounts involved in
|
||||
// each range check. This is a value estimated based on experience. If this
|
||||
// range is too large, the failure rate of range proof will increase. Otherwise,
|
||||
@@ -591,10 +585,10 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
|
||||
if accMarker == nil || !bytes.Equal(account[:], accMarker) {
|
||||
dataLen := len(val) // Approximate size, saves us a round of RLP-encoding
|
||||
if !write {
|
||||
if bytes.Equal(acc.CodeHash, emptyCode[:]) {
|
||||
if bytes.Equal(acc.CodeHash, types.EmptyCodeHash[:]) {
|
||||
dataLen -= 32
|
||||
}
|
||||
if acc.Root == emptyRoot {
|
||||
if acc.Root == types.EmptyRootHash {
|
||||
dataLen -= 32
|
||||
}
|
||||
snapRecoveredAccountMeter.Mark(1)
|
||||
@@ -621,7 +615,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er
|
||||
|
||||
// If the iterated account is the contract, create a further loop to
|
||||
// verify or regenerate the contract storage.
|
||||
if acc.Root == emptyRoot {
|
||||
if acc.Root == types.EmptyRootHash {
|
||||
ctx.removeStorageAt(account)
|
||||
} else {
|
||||
var storeMarker []byte
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -49,9 +50,9 @@ func TestGeneration(t *testing.T) {
|
||||
var helper = newHelper()
|
||||
stRoot := helper.makeStorageTrie(common.Hash{}, common.Hash{}, []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, false)
|
||||
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()})
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
@@ -83,16 +84,16 @@ func TestGenerateExistentState(t *testing.T) {
|
||||
var helper = newHelper()
|
||||
|
||||
stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addSnapAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
|
||||
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()})
|
||||
helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()})
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
|
||||
|
||||
root, snap := helper.CommitAndGenerate()
|
||||
@@ -235,28 +236,28 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) {
|
||||
helper := newHelper()
|
||||
|
||||
// Account one, empty root but non-empty database
|
||||
helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
|
||||
|
||||
// Account two, non empty root but empty database
|
||||
stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-2")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
// Miss slots
|
||||
{
|
||||
// Account three, non empty root but misses slots in the beginning
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-3", []string{"key-2", "key-3"}, []string{"val-2", "val-3"})
|
||||
|
||||
// Account four, non empty root but misses slots in the middle
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-4")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-4", []string{"key-1", "key-3"}, []string{"val-1", "val-3"})
|
||||
|
||||
// Account five, non empty root but misses slots in the end
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-5")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-5", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-5", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-5", []string{"key-1", "key-2"}, []string{"val-1", "val-2"})
|
||||
}
|
||||
|
||||
@@ -264,22 +265,22 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) {
|
||||
{
|
||||
// Account six, non empty root but wrong slots in the beginning
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-6")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-6", []string{"key-1", "key-2", "key-3"}, []string{"badval-1", "val-2", "val-3"})
|
||||
|
||||
// Account seven, non empty root but wrong slots in the middle
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-7")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-7", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-7", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-7", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "badval-2", "val-3"})
|
||||
|
||||
// Account eight, non empty root but wrong slots in the end
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-8")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-8", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-8", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-8", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "badval-3"})
|
||||
|
||||
// Account 9, non empty root but rotated slots
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-9")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-9", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-9", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-9", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-3", "val-2"})
|
||||
}
|
||||
|
||||
@@ -287,17 +288,17 @@ func TestGenerateExistentStateWithWrongStorage(t *testing.T) {
|
||||
{
|
||||
// Account 10, non empty root but extra slots in the beginning
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-10")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-10", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-10", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-10", []string{"key-0", "key-1", "key-2", "key-3"}, []string{"val-0", "val-1", "val-2", "val-3"})
|
||||
|
||||
// Account 11, non empty root but extra slots in the middle
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-11")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-11", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-11", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-11", []string{"key-1", "key-2", "key-2-1", "key-3"}, []string{"val-1", "val-2", "val-2-1", "val-3"})
|
||||
|
||||
// Account 12, non empty root but extra slots in the end
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-12")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-12", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-12", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapStorage("acc-12", []string{"key-1", "key-2", "key-3", "key-4"}, []string{"val-1", "val-2", "val-3", "val-4"})
|
||||
}
|
||||
|
||||
@@ -337,25 +338,25 @@ func TestGenerateExistentStateWithWrongAccounts(t *testing.T) {
|
||||
|
||||
// Missing accounts, only in the trie
|
||||
{
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // Beginning
|
||||
helper.addTrieAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // Middle
|
||||
helper.addTrieAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // End
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Beginning
|
||||
helper.addTrieAccount("acc-4", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // Middle
|
||||
helper.addTrieAccount("acc-6", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // End
|
||||
}
|
||||
|
||||
// Wrong accounts
|
||||
{
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-2", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: common.Hex2Bytes("0x1234")})
|
||||
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()})
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addSnapAccount("acc-3", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
}
|
||||
|
||||
// Extra accounts, only in the snap
|
||||
{
|
||||
helper.addSnapAccount("acc-0", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyRoot.Bytes()}) // before the beginning
|
||||
helper.addSnapAccount("acc-5", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: common.Hex2Bytes("0x1234")}) // Middle
|
||||
helper.addSnapAccount("acc-7", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyRoot.Bytes()}) // after the end
|
||||
helper.addSnapAccount("acc-0", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // before the beginning
|
||||
helper.addSnapAccount("acc-5", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: common.Hex2Bytes("0x1234")}) // Middle
|
||||
helper.addSnapAccount("acc-7", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // after the end
|
||||
}
|
||||
|
||||
root, snap := helper.CommitAndGenerate()
|
||||
@@ -384,9 +385,9 @@ func TestGenerateCorruptAccountTrie(t *testing.T) {
|
||||
// without any storage slots to keep the test smaller.
|
||||
helper := newHelper()
|
||||
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0xc7a30f39aff471c95d8a837497ad0e49b65be475cc0953540f80cfcdbdcd9074
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x19ead688e907b0fab07176120dceec244a72aff2f0aa51e8b827584e378772f4
|
||||
|
||||
root := helper.Commit() // Root: 0xa04693ea110a31037fb5ee814308a6f1d76bdab0b11676bdf4541d2de55ba978
|
||||
|
||||
@@ -419,10 +420,10 @@ func TestGenerateMissingStorageTrie(t *testing.T) {
|
||||
helper := newHelper()
|
||||
|
||||
stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
||||
stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
|
||||
|
||||
root := helper.Commit()
|
||||
|
||||
@@ -453,10 +454,10 @@ func TestGenerateCorruptStorageTrie(t *testing.T) {
|
||||
helper := newHelper()
|
||||
|
||||
stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true) // 0xddefcd9376dd029653ef384bd2f0a126bb755fe84fdcc9e7cf421ba454f2bc67
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}) // 0x65145f923027566669a1ae5ccac66f945b55ff6eaeb17d2ea8e048b7d381f2d7
|
||||
stRoot = helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}) // 0x50815097425d000edfc8b3a4a13e175fc2bdcfee8bdfbf2d1ff61041d3c235b2
|
||||
|
||||
root := helper.Commit()
|
||||
|
||||
@@ -488,7 +489,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) {
|
||||
[]string{"val-1", "val-2", "val-3", "val-4", "val-5"},
|
||||
true,
|
||||
)
|
||||
acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}
|
||||
acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
val, _ := rlp.EncodeToBytes(acc)
|
||||
helper.accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||
|
||||
@@ -508,7 +509,7 @@ func TestGenerateWithExtraAccounts(t *testing.T) {
|
||||
[]string{"val-1", "val-2", "val-3", "val-4", "val-5"},
|
||||
true,
|
||||
)
|
||||
acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}
|
||||
acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
val, _ := rlp.EncodeToBytes(acc)
|
||||
key := hashData([]byte("acc-2"))
|
||||
rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
|
||||
@@ -559,7 +560,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) {
|
||||
[]string{"val-1", "val-2", "val-3"},
|
||||
true,
|
||||
)
|
||||
acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()}
|
||||
acc := &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
val, _ := rlp.EncodeToBytes(acc)
|
||||
helper.accTrie.Update([]byte("acc-1"), val) // 0x9250573b9c18c664139f3b6a7a8081b7d8f8916a8fcc5d94feec6c29f5fd4e9e
|
||||
|
||||
@@ -573,8 +574,7 @@ func TestGenerateWithManyExtraAccounts(t *testing.T) {
|
||||
{
|
||||
// 100 accounts exist only in snapshot
|
||||
for i := 0; i < 1000; i++ {
|
||||
//acc := &Account{Balance: big.NewInt(int64(i)), Root: stTrie.Hash().Bytes(), CodeHash: emptyCode.Bytes()}
|
||||
acc := &Account{Balance: big.NewInt(int64(i)), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
|
||||
acc := &Account{Balance: big.NewInt(int64(i)), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
val, _ := rlp.EncodeToBytes(acc)
|
||||
key := hashData([]byte(fmt.Sprintf("acc-%d", i)))
|
||||
rawdb.WriteAccountSnapshot(helper.diskdb, key, val)
|
||||
@@ -611,7 +611,7 @@ func TestGenerateWithExtraBeforeAndAfter(t *testing.T) {
|
||||
}
|
||||
helper := newHelper()
|
||||
{
|
||||
acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
|
||||
acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
val, _ := rlp.EncodeToBytes(acc)
|
||||
helper.accTrie.Update(common.HexToHash("0x03").Bytes(), val)
|
||||
helper.accTrie.Update(common.HexToHash("0x07").Bytes(), val)
|
||||
@@ -648,7 +648,7 @@ func TestGenerateWithMalformedSnapdata(t *testing.T) {
|
||||
}
|
||||
helper := newHelper()
|
||||
{
|
||||
acc := &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()}
|
||||
acc := &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()}
|
||||
val, _ := rlp.EncodeToBytes(acc)
|
||||
helper.accTrie.Update(common.HexToHash("0x03").Bytes(), val)
|
||||
|
||||
@@ -687,7 +687,7 @@ func TestGenerateFromEmptySnap(t *testing.T) {
|
||||
for i := 0; i < 400; i++ {
|
||||
stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte(fmt.Sprintf("acc-%d", i))), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount(fmt.Sprintf("acc-%d", i),
|
||||
&Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
&Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
}
|
||||
root, snap := helper.CommitAndGenerate()
|
||||
t.Logf("Root: %#x\n", root) // Root: 0x6f7af6d2e1a1bf2b84a3beb3f8b64388465fbc1e274ca5d5d3fc787ca78f59e4
|
||||
@@ -724,7 +724,7 @@ func TestGenerateWithIncompleteStorage(t *testing.T) {
|
||||
for i := 0; i < 8; i++ {
|
||||
accKey := fmt.Sprintf("acc-%d", i)
|
||||
stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte(accKey)), stKeys, stVals, true)
|
||||
helper.addAccount(accKey, &Account{Balance: big.NewInt(int64(i)), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount(accKey, &Account{Balance: big.NewInt(int64(i)), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
var moddedKeys []string
|
||||
var moddedVals []string
|
||||
for ii := 0; ii < 8; ii++ {
|
||||
@@ -816,11 +816,11 @@ func TestGenerateCompleteSnapshotWithDanglingStorage(t *testing.T) {
|
||||
var helper = newHelper()
|
||||
|
||||
stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addAccount("acc-2", &Account{Balance: big.NewInt(1), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addAccount("acc-3", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
helper.addSnapStorage("acc-1", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
|
||||
helper.addSnapStorage("acc-3", []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"})
|
||||
@@ -851,11 +851,11 @@ func TestGenerateBrokenSnapshotWithDanglingStorage(t *testing.T) {
|
||||
var helper = newHelper()
|
||||
|
||||
stRoot := helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-1")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: emptyRoot.Bytes(), CodeHash: emptyCode.Bytes()})
|
||||
helper.addTrieAccount("acc-1", &Account{Balance: big.NewInt(1), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
helper.addTrieAccount("acc-2", &Account{Balance: big.NewInt(2), Root: types.EmptyRootHash.Bytes(), CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
helper.makeStorageTrie(common.Hash{}, hashData([]byte("acc-3")), []string{"key-1", "key-2", "key-3"}, []string{"val-1", "val-2", "val-3"}, true)
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: emptyCode.Bytes()})
|
||||
helper.addTrieAccount("acc-3", &Account{Balance: big.NewInt(3), Root: stRoot, CodeHash: types.EmptyCodeHash.Bytes()})
|
||||
|
||||
populateDangling(helper.diskdb)
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/VictoriaMetrics/fastcache"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
@@ -47,7 +48,7 @@ func randomAccount() []byte {
|
||||
Balance: big.NewInt(rand.Int63()),
|
||||
Nonce: rand.Uint64(),
|
||||
Root: root[:],
|
||||
CodeHash: emptyCode[:],
|
||||
CodeHash: types.EmptyCodeHash[:],
|
||||
}
|
||||
data, _ := rlp.EncodeToBytes(a)
|
||||
return data
|
||||
|
||||
@@ -31,8 +31,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
|
||||
var emptyCodeHash = crypto.Keccak256(nil)
|
||||
|
||||
type Code []byte
|
||||
|
||||
func (c Code) String() string {
|
||||
@@ -95,7 +93,7 @@ type stateObject struct {
|
||||
|
||||
// empty returns whether the account is considered empty.
|
||||
func (s *stateObject) empty() bool {
|
||||
return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash)
|
||||
return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, types.EmptyCodeHash.Bytes())
|
||||
}
|
||||
|
||||
// newObject creates a state object.
|
||||
@@ -104,10 +102,10 @@ func newObject(db *StateDB, address common.Address, data types.StateAccount) *st
|
||||
data.Balance = new(big.Int)
|
||||
}
|
||||
if data.CodeHash == nil {
|
||||
data.CodeHash = emptyCodeHash
|
||||
data.CodeHash = types.EmptyCodeHash.Bytes()
|
||||
}
|
||||
if data.Root == (common.Hash{}) {
|
||||
data.Root = emptyRoot
|
||||
data.Root = types.EmptyRootHash
|
||||
}
|
||||
return &stateObject{
|
||||
db: db,
|
||||
@@ -154,7 +152,7 @@ func (s *stateObject) getTrie(db Database) (Trie, error) {
|
||||
if s.trie == nil {
|
||||
// Try fetching from prefetcher first
|
||||
// We don't prefetch empty tries
|
||||
if s.data.Root != emptyRoot && s.db.prefetcher != nil {
|
||||
if s.data.Root != types.EmptyRootHash && s.db.prefetcher != nil {
|
||||
// When the miner is creating the pending state, there is no
|
||||
// prefetcher
|
||||
s.trie = s.db.prefetcher.trie(s.addrHash, s.data.Root)
|
||||
@@ -270,7 +268,7 @@ func (s *stateObject) finalise(prefetch bool) {
|
||||
slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure
|
||||
}
|
||||
}
|
||||
if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != emptyRoot {
|
||||
if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash {
|
||||
s.db.prefetcher.prefetch(s.addrHash, s.data.Root, slotsToPrefetch)
|
||||
}
|
||||
if len(s.dirtyStorage) > 0 {
|
||||
@@ -454,7 +452,7 @@ func (s *stateObject) Code(db Database) []byte {
|
||||
if s.code != nil {
|
||||
return s.code
|
||||
}
|
||||
if bytes.Equal(s.CodeHash(), emptyCodeHash) {
|
||||
if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) {
|
||||
return nil
|
||||
}
|
||||
code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash()))
|
||||
@@ -472,7 +470,7 @@ func (s *stateObject) CodeSize(db Database) int {
|
||||
if s.code != nil {
|
||||
return len(s.code)
|
||||
}
|
||||
if bytes.Equal(s.CodeHash(), emptyCodeHash) {
|
||||
if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) {
|
||||
return 0
|
||||
}
|
||||
size, err := db.ContractCodeSize(s.addrHash, common.BytesToHash(s.CodeHash()))
|
||||
|
||||
@@ -41,11 +41,6 @@ type revision struct {
|
||||
journalIndex int
|
||||
}
|
||||
|
||||
var (
|
||||
// emptyRoot is the known root hash of an empty trie.
|
||||
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
)
|
||||
|
||||
type proofList [][]byte
|
||||
|
||||
func (n *proofList) Put(key []byte, value []byte) error {
|
||||
@@ -580,10 +575,10 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
|
||||
Root: common.BytesToHash(acc.Root),
|
||||
}
|
||||
if len(data.CodeHash) == 0 {
|
||||
data.CodeHash = emptyCodeHash
|
||||
data.CodeHash = types.EmptyCodeHash.Bytes()
|
||||
}
|
||||
if data.Root == (common.Hash{}) {
|
||||
data.Root = emptyRoot
|
||||
data.Root = types.EmptyRootHash
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1066,11 +1061,11 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
|
||||
s.stateObjectsDestruct = make(map[common.Address]struct{})
|
||||
}
|
||||
if root == (common.Hash{}) {
|
||||
root = emptyRoot
|
||||
root = types.EmptyRootHash
|
||||
}
|
||||
origin := s.originalRoot
|
||||
if origin == (common.Hash{}) {
|
||||
origin = emptyRoot
|
||||
origin = types.EmptyRootHash
|
||||
}
|
||||
if root != origin {
|
||||
start := time.Now()
|
||||
|
||||
@@ -134,8 +134,7 @@ func checkStateConsistency(db ethdb.Database, root common.Hash) error {
|
||||
// Tests that an empty state is not scheduled for syncing.
|
||||
func TestEmptyStateSync(t *testing.T) {
|
||||
db := trie.NewDatabase(rawdb.NewMemoryDatabase())
|
||||
empty := common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
sync := NewStateSync(empty, rawdb.NewMemoryDatabase(), nil, db.Scheme())
|
||||
sync := NewStateSync(types.EmptyRootHash, rawdb.NewMemoryDatabase(), nil, db.Scheme())
|
||||
if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 {
|
||||
t.Errorf("content requested for empty state: %v, %v, %v", nodes, paths, codes)
|
||||
}
|
||||
@@ -555,7 +554,7 @@ func TestIncompleteStateSync(t *testing.T) {
|
||||
isCode[crypto.Keccak256Hash(acc.code)] = struct{}{}
|
||||
}
|
||||
}
|
||||
isCode[common.BytesToHash(emptyCodeHash)] = struct{}{}
|
||||
isCode[types.EmptyCodeHash] = struct{}{}
|
||||
checkTrieConsistency(db, srcRoot)
|
||||
|
||||
// Create a destination state and sync with the scheduler
|
||||
|
||||
@@ -63,7 +63,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
||||
return
|
||||
}
|
||||
// Convert the transaction into an executable message and pre-cache its sender
|
||||
msg, err := tx.AsMessage(signer, header.BaseFee)
|
||||
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
|
||||
if err != nil {
|
||||
return // Also invalid block, bail out
|
||||
}
|
||||
@@ -85,7 +85,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
||||
// precacheTransaction attempts to apply a transaction to the given state database
|
||||
// and uses the input parameters for its environment. The goal is not to execute
|
||||
// the transaction successfully, rather to warm up touched data slots.
|
||||
func precacheTransaction(msg types.Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error {
|
||||
func precacheTransaction(msg *Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error {
|
||||
// Update the evm with the new transaction context.
|
||||
evm.Reset(NewEVMTxContext(msg), statedb)
|
||||
// Add addresses to access list if applicable
|
||||
|
||||
@@ -74,7 +74,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
|
||||
// Iterate over and process the individual transactions
|
||||
for i, tx := range block.Transactions() {
|
||||
msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee)
|
||||
msg, err := TransactionToMessage(tx, types.MakeSigner(p.config, header.Number), header.BaseFee)
|
||||
if err != nil {
|
||||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
@@ -97,7 +97,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||
return receipts, allLogs, *usedGas, nil
|
||||
}
|
||||
|
||||
func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
|
||||
func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
|
||||
// Create a new context to be used in the EVM environment.
|
||||
txContext := NewEVMTxContext(msg)
|
||||
evm.Reset(txContext, statedb)
|
||||
@@ -129,7 +129,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool
|
||||
receipt.GasUsed = result.UsedGas
|
||||
|
||||
// If the transaction created a contract, store the creation address in the receipt.
|
||||
if msg.To() == nil {
|
||||
if msg.To == nil {
|
||||
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool
|
||||
// for the transaction, gas used and an error if the transaction failed,
|
||||
// indicating the block was invalid.
|
||||
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
|
||||
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number), header.BaseFee)
|
||||
msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number), header.BaseFee)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -404,7 +404,7 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
|
||||
header.BaseFee = misc.CalcBaseFee(config, parent.Header())
|
||||
}
|
||||
if config.IsShanghai(header.Time) {
|
||||
header.WithdrawalsHash = &types.EmptyRootHash
|
||||
header.WithdrawalsHash = &types.EmptyWithdrawalsHash
|
||||
}
|
||||
var receipts []*types.Receipt
|
||||
// The post-state result doesn't need to be correct (this is a bad block), but we do need something there
|
||||
|
||||
@@ -25,65 +25,9 @@ import (
|
||||
cmath "github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
var emptyCodeHash = crypto.Keccak256Hash(nil)
|
||||
|
||||
// StateTransition represents a state transition.
|
||||
//
|
||||
// == The State Transitioning Model
|
||||
//
|
||||
// A state transition is a change made when a transaction is applied to the current world
|
||||
// state. The state transitioning model does all the necessary work to work out a valid new
|
||||
// state root.
|
||||
//
|
||||
// 1. Nonce handling
|
||||
// 2. Pre pay gas
|
||||
// 3. Create a new state object if the recipient is nil
|
||||
// 4. Value transfer
|
||||
//
|
||||
// == If contract creation ==
|
||||
//
|
||||
// 4a. Attempt to run transaction data
|
||||
// 4b. If valid, use result as code for the new state object
|
||||
//
|
||||
// == end ==
|
||||
//
|
||||
// 5. Run Script section
|
||||
// 6. Derive new state root
|
||||
type StateTransition struct {
|
||||
gp *GasPool
|
||||
msg Message
|
||||
gas uint64
|
||||
gasPrice *big.Int
|
||||
gasFeeCap *big.Int
|
||||
gasTipCap *big.Int
|
||||
initialGas uint64
|
||||
value *big.Int
|
||||
data []byte
|
||||
state vm.StateDB
|
||||
evm *vm.EVM
|
||||
}
|
||||
|
||||
// Message represents a message sent to a contract.
|
||||
type Message interface {
|
||||
From() common.Address
|
||||
To() *common.Address
|
||||
|
||||
GasPrice() *big.Int
|
||||
GasFeeCap() *big.Int
|
||||
GasTipCap() *big.Int
|
||||
Gas() uint64
|
||||
Value() *big.Int
|
||||
|
||||
Nonce() uint64
|
||||
IsFake() bool
|
||||
Data() []byte
|
||||
AccessList() types.AccessList
|
||||
}
|
||||
|
||||
// ExecutionResult includes all output after executing given evm
|
||||
// message no matter the execution itself is successful or not.
|
||||
type ExecutionResult struct {
|
||||
@@ -178,19 +122,47 @@ func toWordSize(size uint64) uint64 {
|
||||
return (size + 31) / 32
|
||||
}
|
||||
|
||||
// NewStateTransition initialises and returns a new state transition object.
|
||||
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
|
||||
return &StateTransition{
|
||||
gp: gp,
|
||||
evm: evm,
|
||||
msg: msg,
|
||||
gasPrice: msg.GasPrice(),
|
||||
gasFeeCap: msg.GasFeeCap(),
|
||||
gasTipCap: msg.GasTipCap(),
|
||||
value: msg.Value(),
|
||||
data: msg.Data(),
|
||||
state: evm.StateDB,
|
||||
// A Message contains the data derived from a single transaction that is relevant to state
|
||||
// processing.
|
||||
type Message struct {
|
||||
To *common.Address
|
||||
From common.Address
|
||||
Nonce uint64
|
||||
Value *big.Int
|
||||
GasLimit uint64
|
||||
GasPrice *big.Int
|
||||
GasFeeCap *big.Int
|
||||
GasTipCap *big.Int
|
||||
Data []byte
|
||||
AccessList types.AccessList
|
||||
|
||||
// When SkipAccountCheckss is true, the message nonce is not checked against the
|
||||
// account nonce in state. It also disables checking that the sender is an EOA.
|
||||
// This field will be set to true for operations like RPC eth_call.
|
||||
SkipAccountChecks bool
|
||||
}
|
||||
|
||||
// TransactionToMessage converts a transaction into a Message.
|
||||
func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int) (*Message, error) {
|
||||
msg := &Message{
|
||||
Nonce: tx.Nonce(),
|
||||
GasLimit: tx.Gas(),
|
||||
GasPrice: new(big.Int).Set(tx.GasPrice()),
|
||||
GasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
|
||||
GasTipCap: new(big.Int).Set(tx.GasTipCap()),
|
||||
To: tx.To(),
|
||||
Value: tx.Value(),
|
||||
Data: tx.Data(),
|
||||
AccessList: tx.AccessList(),
|
||||
SkipAccountChecks: false,
|
||||
}
|
||||
// If baseFee provided, set gasPrice to effectiveGasPrice.
|
||||
if baseFee != nil {
|
||||
msg.GasPrice = cmath.BigMin(msg.GasPrice.Add(msg.GasTipCap, baseFee), msg.GasFeeCap)
|
||||
}
|
||||
var err error
|
||||
msg.From, err = types.Sender(s, tx)
|
||||
return msg, err
|
||||
}
|
||||
|
||||
// ApplyMessage computes the new state by applying the given message
|
||||
@@ -200,82 +172,126 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
|
||||
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
||||
// indicates a core error meaning that the message would always fail for that particular
|
||||
// state and would never be accepted within a block.
|
||||
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) {
|
||||
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) {
|
||||
return NewStateTransition(evm, msg, gp).TransitionDb()
|
||||
}
|
||||
|
||||
// StateTransition represents a state transition.
|
||||
//
|
||||
// == The State Transitioning Model
|
||||
//
|
||||
// A state transition is a change made when a transaction is applied to the current world
|
||||
// state. The state transitioning model does all the necessary work to work out a valid new
|
||||
// state root.
|
||||
//
|
||||
// 1. Nonce handling
|
||||
// 2. Pre pay gas
|
||||
// 3. Create a new state object if the recipient is nil
|
||||
// 4. Value transfer
|
||||
//
|
||||
// == If contract creation ==
|
||||
//
|
||||
// 4a. Attempt to run transaction data
|
||||
// 4b. If valid, use result as code for the new state object
|
||||
//
|
||||
// == end ==
|
||||
//
|
||||
// 5. Run Script section
|
||||
// 6. Derive new state root
|
||||
type StateTransition struct {
|
||||
gp *GasPool
|
||||
msg *Message
|
||||
gasRemaining uint64
|
||||
initialGas uint64
|
||||
state vm.StateDB
|
||||
evm *vm.EVM
|
||||
}
|
||||
|
||||
// NewStateTransition initialises and returns a new state transition object.
|
||||
func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition {
|
||||
return &StateTransition{
|
||||
gp: gp,
|
||||
evm: evm,
|
||||
msg: msg,
|
||||
state: evm.StateDB,
|
||||
}
|
||||
}
|
||||
|
||||
// to returns the recipient of the message.
|
||||
func (st *StateTransition) to() common.Address {
|
||||
if st.msg == nil || st.msg.To() == nil /* contract creation */ {
|
||||
if st.msg == nil || st.msg.To == nil /* contract creation */ {
|
||||
return common.Address{}
|
||||
}
|
||||
return *st.msg.To()
|
||||
return *st.msg.To
|
||||
}
|
||||
|
||||
func (st *StateTransition) buyGas() error {
|
||||
mgval := new(big.Int).SetUint64(st.msg.Gas())
|
||||
mgval = mgval.Mul(mgval, st.gasPrice)
|
||||
mgval := new(big.Int).SetUint64(st.msg.GasLimit)
|
||||
mgval = mgval.Mul(mgval, st.msg.GasPrice)
|
||||
balanceCheck := mgval
|
||||
if st.gasFeeCap != nil {
|
||||
balanceCheck = new(big.Int).SetUint64(st.msg.Gas())
|
||||
balanceCheck = balanceCheck.Mul(balanceCheck, st.gasFeeCap)
|
||||
balanceCheck.Add(balanceCheck, st.value)
|
||||
if st.msg.GasFeeCap != nil {
|
||||
balanceCheck = new(big.Int).SetUint64(st.msg.GasLimit)
|
||||
balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap)
|
||||
balanceCheck.Add(balanceCheck, st.msg.Value)
|
||||
}
|
||||
if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 {
|
||||
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want)
|
||||
if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 {
|
||||
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want)
|
||||
}
|
||||
if err := st.gp.SubGas(st.msg.Gas()); err != nil {
|
||||
if err := st.gp.SubGas(st.msg.GasLimit); err != nil {
|
||||
return err
|
||||
}
|
||||
st.gas += st.msg.Gas()
|
||||
st.gasRemaining += st.msg.GasLimit
|
||||
|
||||
st.initialGas = st.msg.Gas()
|
||||
st.state.SubBalance(st.msg.From(), mgval)
|
||||
st.initialGas = st.msg.GasLimit
|
||||
st.state.SubBalance(st.msg.From, mgval)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *StateTransition) preCheck() error {
|
||||
// Only check transactions that are not fake
|
||||
if !st.msg.IsFake() {
|
||||
msg := st.msg
|
||||
if !msg.SkipAccountChecks {
|
||||
// Make sure this transaction's nonce is correct.
|
||||
stNonce := st.state.GetNonce(st.msg.From())
|
||||
if msgNonce := st.msg.Nonce(); stNonce < msgNonce {
|
||||
stNonce := st.state.GetNonce(msg.From)
|
||||
if msgNonce := msg.Nonce; stNonce < msgNonce {
|
||||
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
|
||||
st.msg.From().Hex(), msgNonce, stNonce)
|
||||
msg.From.Hex(), msgNonce, stNonce)
|
||||
} else if stNonce > msgNonce {
|
||||
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
|
||||
st.msg.From().Hex(), msgNonce, stNonce)
|
||||
msg.From.Hex(), msgNonce, stNonce)
|
||||
} else if stNonce+1 < stNonce {
|
||||
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
|
||||
st.msg.From().Hex(), stNonce)
|
||||
msg.From.Hex(), stNonce)
|
||||
}
|
||||
// Make sure the sender is an EOA
|
||||
if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
|
||||
codeHash := st.state.GetCodeHash(msg.From)
|
||||
if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash {
|
||||
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
|
||||
st.msg.From().Hex(), codeHash)
|
||||
msg.From.Hex(), codeHash)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
|
||||
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
|
||||
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
|
||||
if !st.evm.Config.NoBaseFee || st.gasFeeCap.BitLen() > 0 || st.gasTipCap.BitLen() > 0 {
|
||||
if l := st.gasFeeCap.BitLen(); l > 256 {
|
||||
if !st.evm.Config.NoBaseFee || msg.GasFeeCap.BitLen() > 0 || msg.GasTipCap.BitLen() > 0 {
|
||||
if l := msg.GasFeeCap.BitLen(); l > 256 {
|
||||
return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
|
||||
st.msg.From().Hex(), l)
|
||||
msg.From.Hex(), l)
|
||||
}
|
||||
if l := st.gasTipCap.BitLen(); l > 256 {
|
||||
if l := msg.GasTipCap.BitLen(); l > 256 {
|
||||
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh,
|
||||
st.msg.From().Hex(), l)
|
||||
msg.From.Hex(), l)
|
||||
}
|
||||
if st.gasFeeCap.Cmp(st.gasTipCap) < 0 {
|
||||
if msg.GasFeeCap.Cmp(msg.GasTipCap) < 0 {
|
||||
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap,
|
||||
st.msg.From().Hex(), st.gasTipCap, st.gasFeeCap)
|
||||
msg.From.Hex(), msg.GasTipCap, msg.GasFeeCap)
|
||||
}
|
||||
// This will panic if baseFee is nil, but basefee presence is verified
|
||||
// as part of header validation.
|
||||
if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
|
||||
if msg.GasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
|
||||
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
|
||||
st.msg.From().Hex(), st.gasFeeCap, st.evm.Context.BaseFee)
|
||||
msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -311,52 +327,52 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||
if st.evm.Config.Debug {
|
||||
st.evm.Config.Tracer.CaptureTxStart(st.initialGas)
|
||||
defer func() {
|
||||
st.evm.Config.Tracer.CaptureTxEnd(st.gas)
|
||||
st.evm.Config.Tracer.CaptureTxEnd(st.gasRemaining)
|
||||
}()
|
||||
}
|
||||
|
||||
var (
|
||||
msg = st.msg
|
||||
sender = vm.AccountRef(msg.From())
|
||||
sender = vm.AccountRef(msg.From)
|
||||
rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time)
|
||||
contractCreation = msg.To() == nil
|
||||
contractCreation = msg.To == nil
|
||||
)
|
||||
|
||||
// Check clauses 4-5, subtract intrinsic gas if everything is correct
|
||||
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
|
||||
gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if st.gas < gas {
|
||||
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas)
|
||||
if st.gasRemaining < gas {
|
||||
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
|
||||
}
|
||||
st.gas -= gas
|
||||
st.gasRemaining -= gas
|
||||
|
||||
// Check clause 6
|
||||
if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) {
|
||||
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex())
|
||||
if msg.Value.Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From, msg.Value) {
|
||||
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())
|
||||
}
|
||||
|
||||
// Check whether the init code size has been exceeded.
|
||||
if rules.IsShanghai && contractCreation && len(st.data) > params.MaxInitCodeSize {
|
||||
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize)
|
||||
if rules.IsShanghai && contractCreation && len(msg.Data) > params.MaxInitCodeSize {
|
||||
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize)
|
||||
}
|
||||
|
||||
// Execute the preparatory steps for state transition which includes:
|
||||
// - prepare accessList(post-berlin)
|
||||
// - reset transient storage(eip 1153)
|
||||
st.state.Prepare(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
|
||||
st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList)
|
||||
|
||||
var (
|
||||
ret []byte
|
||||
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
|
||||
)
|
||||
if contractCreation {
|
||||
ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value)
|
||||
ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, msg.Value)
|
||||
} else {
|
||||
// Increment the nonce for the next transaction
|
||||
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
|
||||
ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value)
|
||||
st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1)
|
||||
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value)
|
||||
}
|
||||
|
||||
if !rules.IsLondon {
|
||||
@@ -366,12 +382,12 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||
// After EIP-3529: refunds are capped to gasUsed / 5
|
||||
st.refundGas(params.RefundQuotientEIP3529)
|
||||
}
|
||||
effectiveTip := st.gasPrice
|
||||
effectiveTip := msg.GasPrice
|
||||
if rules.IsLondon {
|
||||
effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee))
|
||||
effectiveTip = cmath.BigMin(msg.GasTipCap, new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee))
|
||||
}
|
||||
|
||||
if st.evm.Config.NoBaseFee && st.gasFeeCap.Sign() == 0 && st.gasTipCap.Sign() == 0 {
|
||||
if st.evm.Config.NoBaseFee && msg.GasFeeCap.Sign() == 0 && msg.GasTipCap.Sign() == 0 {
|
||||
// Skip fee payment when NoBaseFee is set and the fee fields
|
||||
// are 0. This avoids a negative effectiveTip being applied to
|
||||
// the coinbase when simulating calls.
|
||||
@@ -394,18 +410,18 @@ func (st *StateTransition) refundGas(refundQuotient uint64) {
|
||||
if refund > st.state.GetRefund() {
|
||||
refund = st.state.GetRefund()
|
||||
}
|
||||
st.gas += refund
|
||||
st.gasRemaining += refund
|
||||
|
||||
// Return ETH for remaining gas, exchanged at the original rate.
|
||||
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
|
||||
st.state.AddBalance(st.msg.From(), remaining)
|
||||
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice)
|
||||
st.state.AddBalance(st.msg.From, remaining)
|
||||
|
||||
// Also return remaining gas to the block gas counter so it is
|
||||
// available for the next transaction.
|
||||
st.gp.AddGas(st.gas)
|
||||
st.gp.AddGas(st.gasRemaining)
|
||||
}
|
||||
|
||||
// gasUsed returns the amount of gas used up by the state transition.
|
||||
func (st *StateTransition) gasUsed() uint64 {
|
||||
return st.initialGas - st.gas
|
||||
return st.initialGas - st.gasRemaining
|
||||
}
|
||||
|
||||
@@ -254,17 +254,19 @@ type list struct {
|
||||
strict bool // Whether nonces are strictly continuous or not
|
||||
txs *sortedMap // Heap indexed sorted hash map of the transactions
|
||||
|
||||
costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance)
|
||||
gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit)
|
||||
costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance)
|
||||
gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit)
|
||||
totalcost *big.Int // Total cost of all transactions in the list
|
||||
}
|
||||
|
||||
// newList create a new transaction list for maintaining nonce-indexable fast,
|
||||
// gapped, sortable transaction lists.
|
||||
func newList(strict bool) *list {
|
||||
return &list{
|
||||
strict: strict,
|
||||
txs: newSortedMap(),
|
||||
costcap: new(big.Int),
|
||||
strict: strict,
|
||||
txs: newSortedMap(),
|
||||
costcap: new(big.Int),
|
||||
totalcost: new(big.Int),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +304,11 @@ func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transa
|
||||
if tx.GasFeeCapIntCmp(thresholdFeeCap) < 0 || tx.GasTipCapIntCmp(thresholdTip) < 0 {
|
||||
return false, nil
|
||||
}
|
||||
// Old is being replaced, subtract old cost
|
||||
l.subTotalCost([]*types.Transaction{old})
|
||||
}
|
||||
// Add new tx cost to totalcost
|
||||
l.totalcost.Add(l.totalcost, tx.Cost())
|
||||
// Otherwise overwrite the old transaction with the current one
|
||||
l.txs.Put(tx)
|
||||
if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 {
|
||||
@@ -318,7 +324,9 @@ func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transa
|
||||
// provided threshold. Every removed transaction is returned for any post-removal
|
||||
// maintenance.
|
||||
func (l *list) Forward(threshold uint64) types.Transactions {
|
||||
return l.txs.Forward(threshold)
|
||||
txs := l.txs.Forward(threshold)
|
||||
l.subTotalCost(txs)
|
||||
return txs
|
||||
}
|
||||
|
||||
// Filter removes all transactions from the list with a cost or gas limit higher
|
||||
@@ -357,6 +365,9 @@ func (l *list) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions,
|
||||
}
|
||||
invalids = l.txs.filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest })
|
||||
}
|
||||
// Reset total cost
|
||||
l.subTotalCost(removed)
|
||||
l.subTotalCost(invalids)
|
||||
l.txs.reheap()
|
||||
return removed, invalids
|
||||
}
|
||||
@@ -364,7 +375,9 @@ func (l *list) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions,
|
||||
// Cap places a hard limit on the number of items, returning all transactions
|
||||
// exceeding that limit.
|
||||
func (l *list) Cap(threshold int) types.Transactions {
|
||||
return l.txs.Cap(threshold)
|
||||
txs := l.txs.Cap(threshold)
|
||||
l.subTotalCost(txs)
|
||||
return txs
|
||||
}
|
||||
|
||||
// Remove deletes a transaction from the maintained list, returning whether the
|
||||
@@ -376,9 +389,12 @@ func (l *list) Remove(tx *types.Transaction) (bool, types.Transactions) {
|
||||
if removed := l.txs.Remove(nonce); !removed {
|
||||
return false, nil
|
||||
}
|
||||
l.subTotalCost([]*types.Transaction{tx})
|
||||
// In strict mode, filter out non-executable transactions
|
||||
if l.strict {
|
||||
return true, l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce })
|
||||
txs := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce })
|
||||
l.subTotalCost(txs)
|
||||
return true, txs
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
@@ -391,7 +407,9 @@ func (l *list) Remove(tx *types.Transaction) (bool, types.Transactions) {
|
||||
// prevent getting into and invalid state. This is not something that should ever
|
||||
// happen but better to be self correcting than failing!
|
||||
func (l *list) Ready(start uint64) types.Transactions {
|
||||
return l.txs.Ready(start)
|
||||
txs := l.txs.Ready(start)
|
||||
l.subTotalCost(txs)
|
||||
return txs
|
||||
}
|
||||
|
||||
// Len returns the length of the transaction list.
|
||||
@@ -417,6 +435,14 @@ func (l *list) LastElement() *types.Transaction {
|
||||
return l.txs.LastElement()
|
||||
}
|
||||
|
||||
// subTotalCost subtracts the cost of the given transactions from the
|
||||
// total cost of all transactions.
|
||||
func (l *list) subTotalCost(txs []*types.Transaction) {
|
||||
for _, tx := range txs {
|
||||
l.totalcost.Sub(l.totalcost, tx.Cost())
|
||||
}
|
||||
}
|
||||
|
||||
// priceHeap is a heap.Interface implementation over transactions for retrieving
|
||||
// price-sorted transactions to discard when the pool fills up. If baseFee is set
|
||||
// then the heap is sorted based on the effective tip based on the given base fee.
|
||||
@@ -561,6 +587,7 @@ func (l *pricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool {
|
||||
|
||||
// Discard finds a number of most underpriced transactions, removes them from the
|
||||
// priced list and returns them for further removal from the entire pool.
|
||||
// If noPending is set to true, we will only consider the floating list
|
||||
//
|
||||
// Note local transaction won't be considered for eviction.
|
||||
func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package txpool
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -87,6 +88,14 @@ var (
|
||||
// than some meaningful limit a user might use. This is not a consensus error
|
||||
// making the transaction invalid, rather a DOS protection.
|
||||
ErrOversizedData = errors.New("oversized data")
|
||||
|
||||
// ErrFutureReplacePending is returned if a future transaction replaces a pending
|
||||
// transaction. Future transactions should only be able to replace other future transactions.
|
||||
ErrFutureReplacePending = errors.New("future transaction tries to replace pending")
|
||||
|
||||
// ErrOverdraft is returned if a transaction would cause the senders balance to go negative
|
||||
// thus invalidating a potential large number of transactions.
|
||||
ErrOverdraft = errors.New("transaction would cause overdraft")
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -145,7 +154,7 @@ const (
|
||||
// blockChain provides the state of blockchain and current gas limit to do
|
||||
// some pre checks in tx pool and event subscribers.
|
||||
type blockChain interface {
|
||||
CurrentBlock() *types.Block
|
||||
CurrentBlock() *types.Header
|
||||
GetBlock(hash common.Hash, number uint64) *types.Block
|
||||
StateAt(root common.Hash) (*state.StateDB, error)
|
||||
|
||||
@@ -309,7 +318,7 @@ func NewTxPool(config Config, chainconfig *params.ChainConfig, chain blockChain)
|
||||
pool.locals.add(addr)
|
||||
}
|
||||
pool.priced = newPricedList(pool.all)
|
||||
pool.reset(nil, chain.CurrentBlock().Header())
|
||||
pool.reset(nil, chain.CurrentBlock())
|
||||
|
||||
// Start the reorg loop early so it can handle requests generated during journal loading.
|
||||
pool.wg.Add(1)
|
||||
@@ -361,8 +370,8 @@ func (pool *TxPool) loop() {
|
||||
// Handle ChainHeadEvent
|
||||
case ev := <-pool.chainHeadCh:
|
||||
if ev.Block != nil {
|
||||
pool.requestReset(head.Header(), ev.Block.Header())
|
||||
head = ev.Block
|
||||
pool.requestReset(head, ev.Block.Header())
|
||||
head = ev.Block.Header()
|
||||
}
|
||||
|
||||
// System shutdown.
|
||||
@@ -639,9 +648,25 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
|
||||
}
|
||||
// Transactor should have enough funds to cover the costs
|
||||
// cost == V + GP * GL
|
||||
if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 {
|
||||
balance := pool.currentState.GetBalance(from)
|
||||
if balance.Cmp(tx.Cost()) < 0 {
|
||||
return core.ErrInsufficientFunds
|
||||
}
|
||||
|
||||
// Verify that replacing transactions will not result in overdraft
|
||||
list := pool.pending[from]
|
||||
if list != nil { // Sender already has pending txs
|
||||
sum := new(big.Int).Add(tx.Cost(), list.totalcost)
|
||||
if repl := list.txs.Get(tx.Nonce()); repl != nil {
|
||||
// Deduct the cost of a transaction replaced by this
|
||||
sum.Sub(sum, repl.Cost())
|
||||
}
|
||||
if balance.Cmp(sum) < 0 {
|
||||
log.Trace("Replacing transactions would overdraft", "sender", from, "balance", pool.currentState.GetBalance(from), "required", sum)
|
||||
return ErrOverdraft
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the transaction has more gas than the basic tx fee.
|
||||
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai)
|
||||
if err != nil {
|
||||
@@ -678,6 +703,10 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
|
||||
invalidTxMeter.Mark(1)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// already validated by this point
|
||||
from, _ := types.Sender(pool.signer, tx)
|
||||
|
||||
// If the transaction pool is full, discard underpriced transactions
|
||||
if uint64(pool.all.Slots()+numSlots(tx)) > pool.config.GlobalSlots+pool.config.GlobalQueue {
|
||||
// If the new transaction is underpriced, don't accept it
|
||||
@@ -686,6 +715,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
|
||||
underpricedTxMeter.Mark(1)
|
||||
return false, ErrUnderpriced
|
||||
}
|
||||
|
||||
// We're about to replace a transaction. The reorg does a more thorough
|
||||
// analysis of what to remove and how, but it runs async. We don't want to
|
||||
// do too many replacements between reorg-runs, so we cap the number of
|
||||
@@ -706,17 +736,37 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
|
||||
overflowedTxMeter.Mark(1)
|
||||
return false, ErrTxPoolOverflow
|
||||
}
|
||||
// Bump the counter of rejections-since-reorg
|
||||
pool.changesSinceReorg += len(drop)
|
||||
|
||||
// If the new transaction is a future transaction it should never churn pending transactions
|
||||
if pool.isFuture(from, tx) {
|
||||
var replacesPending bool
|
||||
for _, dropTx := range drop {
|
||||
dropSender, _ := types.Sender(pool.signer, dropTx)
|
||||
if list := pool.pending[dropSender]; list != nil && list.Overlaps(dropTx) {
|
||||
replacesPending = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// Add all transactions back to the priced queue
|
||||
if replacesPending {
|
||||
for _, dropTx := range drop {
|
||||
heap.Push(&pool.priced.urgent, dropTx)
|
||||
}
|
||||
log.Trace("Discarding future transaction replacing pending tx", "hash", hash)
|
||||
return false, ErrFutureReplacePending
|
||||
}
|
||||
}
|
||||
|
||||
// Kick out the underpriced remote transactions.
|
||||
for _, tx := range drop {
|
||||
log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
||||
underpricedTxMeter.Mark(1)
|
||||
pool.removeTx(tx.Hash(), false)
|
||||
dropped := pool.removeTx(tx.Hash(), false)
|
||||
pool.changesSinceReorg += dropped
|
||||
}
|
||||
}
|
||||
|
||||
// Try to replace an existing transaction in the pending pool
|
||||
from, _ := types.Sender(pool.signer, tx) // already validated
|
||||
if list := pool.pending[from]; list != nil && list.Overlaps(tx) {
|
||||
// Nonce already pending, check if required price bump is met
|
||||
inserted, old := list.Add(tx, pool.config.PriceBump)
|
||||
@@ -760,6 +810,20 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
|
||||
return replaced, nil
|
||||
}
|
||||
|
||||
// isFuture reports whether the given transaction is immediately executable.
|
||||
func (pool *TxPool) isFuture(from common.Address, tx *types.Transaction) bool {
|
||||
list := pool.pending[from]
|
||||
if list == nil {
|
||||
return pool.pendingNonces.get(from) != tx.Nonce()
|
||||
}
|
||||
// Sender has pending transactions.
|
||||
if old := list.txs.Get(tx.Nonce()); old != nil {
|
||||
return false // It replaces a pending transaction.
|
||||
}
|
||||
// Not replacing, check if parent nonce exists in pending.
|
||||
return list.txs.Get(tx.Nonce()-1) == nil
|
||||
}
|
||||
|
||||
// enqueueTx inserts a new transaction into the non-executable transaction queue.
|
||||
//
|
||||
// Note, this method assumes the pool lock is held!
|
||||
@@ -996,11 +1060,12 @@ func (pool *TxPool) Has(hash common.Hash) bool {
|
||||
|
||||
// removeTx removes a single transaction from the queue, moving all subsequent
|
||||
// transactions back to the future queue.
|
||||
func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
|
||||
// Returns the number of transactions removed from the pending queue.
|
||||
func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) int {
|
||||
// Fetch the transaction we wish to delete
|
||||
tx := pool.all.Get(hash)
|
||||
if tx == nil {
|
||||
return
|
||||
return 0
|
||||
}
|
||||
addr, _ := types.Sender(pool.signer, tx) // already validated during insertion
|
||||
|
||||
@@ -1028,7 +1093,7 @@ func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
|
||||
pool.pendingNonces.setIfLower(addr, tx.Nonce())
|
||||
// Reduce the pending counter
|
||||
pendingGauge.Dec(int64(1 + len(invalids)))
|
||||
return
|
||||
return 1 + len(invalids)
|
||||
}
|
||||
}
|
||||
// Transaction is in the future queue
|
||||
@@ -1042,6 +1107,7 @@ func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
|
||||
delete(pool.beats, addr)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// requestReset requests a pool reset to the new head block.
|
||||
@@ -1291,7 +1357,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
|
||||
}
|
||||
// Initialize the internal state to the current head
|
||||
if newHead == nil {
|
||||
newHead = pool.chain.CurrentBlock().Header() // Special case during testing
|
||||
newHead = pool.chain.CurrentBlock() // Special case during testing
|
||||
}
|
||||
statedb, err := pool.chain.StateAt(newHead.Root)
|
||||
if err != nil {
|
||||
|
||||
212
core/txpool/txpool2_test.go
Normal file
212
core/txpool/txpool2_test.go
Normal file
@@ -0,0 +1,212 @@
|
||||
// Copyright 2023 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
package txpool
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
func pricedValuedTransaction(nonce uint64, value int64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
|
||||
tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(value), gaslimit, gasprice, nil), types.HomesteadSigner{}, key)
|
||||
return tx
|
||||
}
|
||||
|
||||
func count(t *testing.T, pool *TxPool) (pending int, queued int) {
|
||||
t.Helper()
|
||||
pending, queued = pool.stats()
|
||||
if err := validatePoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
return pending, queued
|
||||
}
|
||||
|
||||
func fillPool(t *testing.T, pool *TxPool) {
|
||||
t.Helper()
|
||||
// Create a number of test accounts, fund them and make transactions
|
||||
executableTxs := types.Transactions{}
|
||||
nonExecutableTxs := types.Transactions{}
|
||||
for i := 0; i < 384; i++ {
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000))
|
||||
// Add executable ones
|
||||
for j := 0; j < int(pool.config.AccountSlots); j++ {
|
||||
executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key))
|
||||
}
|
||||
}
|
||||
// Import the batch and verify that limits have been enforced
|
||||
pool.AddRemotesSync(executableTxs)
|
||||
pool.AddRemotesSync(nonExecutableTxs)
|
||||
pending, queued := pool.Stats()
|
||||
slots := pool.all.Slots()
|
||||
// sanity-check that the test prerequisites are ok (pending full)
|
||||
if have, want := pending, slots; have != want {
|
||||
t.Fatalf("have %d, want %d", have, want)
|
||||
}
|
||||
if have, want := queued, 0; have != want {
|
||||
t.Fatalf("have %d, want %d", have, want)
|
||||
}
|
||||
|
||||
t.Logf("pool.config: GlobalSlots=%d, GlobalQueue=%d\n", pool.config.GlobalSlots, pool.config.GlobalQueue)
|
||||
t.Logf("pending: %d queued: %d, all: %d\n", pending, queued, slots)
|
||||
}
|
||||
|
||||
// Tests that if a batch high-priced of non-executables arrive, they do not kick out
|
||||
// executable transactions
|
||||
func TestTransactionFutureAttack(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create the pool to test the limit enforcement with
|
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := &testBlockChain{1000000, statedb, new(event.Feed)}
|
||||
config := testTxPoolConfig
|
||||
config.GlobalQueue = 100
|
||||
config.GlobalSlots = 100
|
||||
pool := NewTxPool(config, eip1559Config, blockchain)
|
||||
defer pool.Stop()
|
||||
fillPool(t, pool)
|
||||
pending, _ := pool.Stats()
|
||||
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||
{
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
futureTxs := types.Transactions{}
|
||||
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
|
||||
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key))
|
||||
}
|
||||
for i := 0; i < 5; i++ {
|
||||
pool.AddRemotesSync(futureTxs)
|
||||
newPending, newQueued := count(t, pool)
|
||||
t.Logf("pending: %d queued: %d, all: %d\n", newPending, newQueued, pool.all.Slots())
|
||||
}
|
||||
}
|
||||
newPending, _ := pool.Stats()
|
||||
// Pending should not have been touched
|
||||
if have, want := newPending, pending; have < want {
|
||||
t.Errorf("wrong pending-count, have %d, want %d (GlobalSlots: %d)",
|
||||
have, want, pool.config.GlobalSlots)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that if a batch high-priced of non-executables arrive, they do not kick out
|
||||
// executable transactions
|
||||
func TestTransactionFuture1559(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Create the pool to test the pricing enforcement with
|
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := &testBlockChain{1000000, statedb, new(event.Feed)}
|
||||
pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain)
|
||||
defer pool.Stop()
|
||||
|
||||
// Create a number of test accounts, fund them and make transactions
|
||||
fillPool(t, pool)
|
||||
pending, _ := pool.Stats()
|
||||
|
||||
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||
{
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
futureTxs := types.Transactions{}
|
||||
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
|
||||
futureTxs = append(futureTxs, dynamicFeeTx(1000+uint64(j), 100000, big.NewInt(200), big.NewInt(101), key))
|
||||
}
|
||||
pool.AddRemotesSync(futureTxs)
|
||||
}
|
||||
newPending, _ := pool.Stats()
|
||||
// Pending should not have been touched
|
||||
if have, want := newPending, pending; have != want {
|
||||
t.Errorf("Wrong pending-count, have %d, want %d (GlobalSlots: %d)",
|
||||
have, want, pool.config.GlobalSlots)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that if a batch of balance-overdraft txs arrive, they do not kick out
|
||||
// executable transactions
|
||||
func TestTransactionZAttack(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Create the pool to test the pricing enforcement with
|
||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
blockchain := &testBlockChain{1000000, statedb, new(event.Feed)}
|
||||
pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain)
|
||||
defer pool.Stop()
|
||||
// Create a number of test accounts, fund them and make transactions
|
||||
fillPool(t, pool)
|
||||
|
||||
countInvalidPending := func() int {
|
||||
t.Helper()
|
||||
var ivpendingNum int
|
||||
pendingtxs, _ := pool.Content()
|
||||
for account, txs := range pendingtxs {
|
||||
cur_balance := new(big.Int).Set(pool.currentState.GetBalance(account))
|
||||
for _, tx := range txs {
|
||||
if cur_balance.Cmp(tx.Value()) <= 0 {
|
||||
ivpendingNum++
|
||||
} else {
|
||||
cur_balance.Sub(cur_balance, tx.Value())
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := validatePoolInternals(pool); err != nil {
|
||||
t.Fatalf("pool internal state corrupted: %v", err)
|
||||
}
|
||||
return ivpendingNum
|
||||
}
|
||||
ivPending := countInvalidPending()
|
||||
t.Logf("invalid pending: %d\n", ivPending)
|
||||
|
||||
// Now, DETER-Z attack starts, let's add a bunch of expensive non-executables (from N accounts) along with balance-overdraft txs (from one account), and see if the pending-count drops
|
||||
for j := 0; j < int(pool.config.GlobalQueue); j++ {
|
||||
futureTxs := types.Transactions{}
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key))
|
||||
pool.AddRemotesSync(futureTxs)
|
||||
}
|
||||
|
||||
overDraftTxs := types.Transactions{}
|
||||
{
|
||||
key, _ := crypto.GenerateKey()
|
||||
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||
for j := 0; j < int(pool.config.GlobalSlots); j++ {
|
||||
overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 60000000000, 21000, big.NewInt(500), key))
|
||||
}
|
||||
}
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
pool.AddRemotesSync(overDraftTxs)
|
||||
|
||||
newPending, newQueued := count(t, pool)
|
||||
newIvPending := countInvalidPending()
|
||||
t.Logf("pool.all.Slots(): %d\n", pool.all.Slots())
|
||||
t.Logf("pending: %d queued: %d, all: %d\n", newPending, newQueued, pool.all.Slots())
|
||||
t.Logf("invalid pending: %d\n", newIvPending)
|
||||
|
||||
// Pending should not have been touched
|
||||
if newIvPending != ivPending {
|
||||
t.Errorf("Wrong invalid pending-count, have %d, want %d (GlobalSlots: %d, queued: %d)",
|
||||
newIvPending, ivPending, pool.config.GlobalSlots, newQueued)
|
||||
}
|
||||
}
|
||||
@@ -64,14 +64,15 @@ type testBlockChain struct {
|
||||
chainHeadFeed *event.Feed
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) CurrentBlock() *types.Block {
|
||||
return types.NewBlock(&types.Header{
|
||||
func (bc *testBlockChain) CurrentBlock() *types.Header {
|
||||
return &types.Header{
|
||||
Number: new(big.Int),
|
||||
GasLimit: atomic.LoadUint64(&bc.gasLimit),
|
||||
}, nil, nil, nil, trie.NewStackTrie(nil))
|
||||
}
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
|
||||
return bc.CurrentBlock()
|
||||
return types.NewBlock(bc.CurrentBlock(), nil, nil, nil, trie.NewStackTrie(nil))
|
||||
}
|
||||
|
||||
func (bc *testBlockChain) StateAt(common.Hash) (*state.StateDB, error) {
|
||||
@@ -157,6 +158,9 @@ func validatePoolInternals(pool *TxPool) error {
|
||||
if nonce := pool.pendingNonces.get(addr); nonce != last+1 {
|
||||
return fmt.Errorf("pending nonce mismatch: have %v, want %v", nonce, last+1)
|
||||
}
|
||||
if txs.totalcost.Cmp(common.Big0) < 0 {
|
||||
return fmt.Errorf("totalcost went negative: %v", txs.totalcost)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1104,7 +1108,7 @@ func TestPendingLimiting(t *testing.T) {
|
||||
defer pool.Stop()
|
||||
|
||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||
testAddBalance(pool, account, big.NewInt(1000000))
|
||||
testAddBalance(pool, account, big.NewInt(1000000000000))
|
||||
|
||||
// Keep track of transaction events to ensure all executables get announced
|
||||
events := make(chan core.NewTxsEvent, testTxPoolConfig.AccountQueue+5)
|
||||
@@ -1583,7 +1587,7 @@ func TestRepricingKeepsLocals(t *testing.T) {
|
||||
keys := make([]*ecdsa.PrivateKey, 3)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000*1000000))
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(100000*1000000))
|
||||
}
|
||||
// Create transaction (both pending and queued) with a linearly growing gasprice
|
||||
for i := uint64(0); i < 500; i++ {
|
||||
@@ -1662,7 +1666,7 @@ func TestUnderpricing(t *testing.T) {
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
// Create a number of test accounts and fund them
|
||||
keys := make([]*ecdsa.PrivateKey, 4)
|
||||
keys := make([]*ecdsa.PrivateKey, 5)
|
||||
for i := 0; i < len(keys); i++ {
|
||||
keys[i], _ = crypto.GenerateKey()
|
||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||
@@ -1698,6 +1702,10 @@ func TestUnderpricing(t *testing.T) {
|
||||
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced {
|
||||
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||
}
|
||||
// Replace a future transaction with a future transaction
|
||||
if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[1])); err != nil { // +K1:1 => -K1:1 => Pend K0:0, K0:1, K2:0; Que K1:1
|
||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||
}
|
||||
// Ensure that adding high priced transactions drops cheap ones, but not own
|
||||
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { // +K1:0 => -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que -
|
||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||
@@ -1708,6 +1716,10 @@ func TestUnderpricing(t *testing.T) {
|
||||
if err := pool.AddRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:3 => -K0:1 => Pend K1:0, K2:0; Que K1:2 K1:3
|
||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||
}
|
||||
// Ensure that replacing a pending transaction with a future transaction fails
|
||||
if err := pool.AddRemote(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); err != ErrFutureReplacePending {
|
||||
t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, ErrFutureReplacePending)
|
||||
}
|
||||
pending, queued = pool.Stats()
|
||||
if pending != 2 {
|
||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||
@@ -1715,7 +1727,7 @@ func TestUnderpricing(t *testing.T) {
|
||||
if queued != 2 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
|
||||
}
|
||||
if err := validateEvents(events, 1); err != nil {
|
||||
if err := validateEvents(events, 2); err != nil {
|
||||
t.Fatalf("additional event firing failed: %v", err)
|
||||
}
|
||||
if err := validatePoolInternals(pool); err != nil {
|
||||
@@ -1877,11 +1889,11 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||
}
|
||||
|
||||
tx = pricedTransaction(2, 100000, big.NewInt(3), keys[1])
|
||||
tx = pricedTransaction(1, 100000, big.NewInt(3), keys[1])
|
||||
if err := pool.AddRemote(tx); err != nil { // +K1:2, -K0:1 => Pend K0:0 K1:0, K2:0; Que K1:2
|
||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||
}
|
||||
tx = dynamicFeeTx(3, 100000, big.NewInt(4), big.NewInt(1), keys[1])
|
||||
tx = dynamicFeeTx(2, 100000, big.NewInt(4), big.NewInt(1), keys[1])
|
||||
if err := pool.AddRemote(tx); err != nil { // +K1:3, -K1:0 => Pend K0:0 K2:0; Que K1:2 K1:3
|
||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||
}
|
||||
@@ -1892,7 +1904,7 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
||||
if queued != 2 {
|
||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
|
||||
}
|
||||
if err := validateEvents(events, 1); err != nil {
|
||||
if err := validateEvents(events, 2); err != nil {
|
||||
t.Fatalf("additional event firing failed: %v", err)
|
||||
}
|
||||
if err := validatePoolInternals(pool); err != nil {
|
||||
@@ -2486,7 +2498,7 @@ func benchmarkBatchInsert(b *testing.B, size int, local bool) {
|
||||
defer pool.Stop()
|
||||
|
||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||
testAddBalance(pool, account, big.NewInt(1000000))
|
||||
testAddBalance(pool, account, big.NewInt(1000000000000000000))
|
||||
|
||||
batches := make([]types.Transactions, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
||||
@@ -31,11 +31,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
var (
|
||||
EmptyRootHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
EmptyUncleHash = rlpHash([]*Header(nil))
|
||||
)
|
||||
|
||||
// A BlockNonce is a 64-bit hash which proves (combined with the
|
||||
// mix-hash) that a sufficient amount of computation has been carried
|
||||
// out on a block.
|
||||
@@ -155,14 +150,14 @@ func (h *Header) SanityCheck() error {
|
||||
// that is: no transactions, no uncles and no withdrawals.
|
||||
func (h *Header) EmptyBody() bool {
|
||||
if h.WithdrawalsHash == nil {
|
||||
return h.TxHash == EmptyRootHash && h.UncleHash == EmptyUncleHash
|
||||
return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash
|
||||
}
|
||||
return h.TxHash == EmptyRootHash && h.UncleHash == EmptyUncleHash && *h.WithdrawalsHash == EmptyRootHash
|
||||
return h.TxHash == EmptyTxsHash && h.UncleHash == EmptyUncleHash && *h.WithdrawalsHash == EmptyWithdrawalsHash
|
||||
}
|
||||
|
||||
// EmptyReceipts returns true if there are no receipts for this header/block.
|
||||
func (h *Header) EmptyReceipts() bool {
|
||||
return h.ReceiptHash == EmptyRootHash
|
||||
return h.ReceiptHash == EmptyReceiptsHash
|
||||
}
|
||||
|
||||
// Body is a simple (mutable, non-safe) data container for storing and moving
|
||||
@@ -210,7 +205,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*
|
||||
|
||||
// TODO: panic if len(txs) != len(receipts)
|
||||
if len(txs) == 0 {
|
||||
b.header.TxHash = EmptyRootHash
|
||||
b.header.TxHash = EmptyTxsHash
|
||||
} else {
|
||||
b.header.TxHash = DeriveSha(Transactions(txs), hasher)
|
||||
b.transactions = make(Transactions, len(txs))
|
||||
@@ -218,7 +213,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*
|
||||
}
|
||||
|
||||
if len(receipts) == 0 {
|
||||
b.header.ReceiptHash = EmptyRootHash
|
||||
b.header.ReceiptHash = EmptyReceiptsHash
|
||||
} else {
|
||||
b.header.ReceiptHash = DeriveSha(Receipts(receipts), hasher)
|
||||
b.header.Bloom = CreateBloom(receipts)
|
||||
@@ -250,7 +245,7 @@ func NewBlockWithWithdrawals(header *Header, txs []*Transaction, uncles []*Heade
|
||||
if withdrawals == nil {
|
||||
b.header.WithdrawalsHash = nil
|
||||
} else if len(withdrawals) == 0 {
|
||||
b.header.WithdrawalsHash = &EmptyRootHash
|
||||
b.header.WithdrawalsHash = &EmptyWithdrawalsHash
|
||||
} else {
|
||||
h := DeriveSha(Withdrawals(withdrawals), hasher)
|
||||
b.header.WithdrawalsHash = &h
|
||||
@@ -284,6 +279,7 @@ func CopyHeader(h *Header) *Header {
|
||||
copy(cpy.Extra, h.Extra)
|
||||
}
|
||||
if h.WithdrawalsHash != nil {
|
||||
cpy.WithdrawalsHash = new(common.Hash)
|
||||
*cpy.WithdrawalsHash = *h.WithdrawalsHash
|
||||
}
|
||||
return &cpy
|
||||
|
||||
@@ -25,6 +25,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
|
||||
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
|
||||
ContractAddress common.Address `json:"contractAddress"`
|
||||
GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||
EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice,omitempty"`
|
||||
BlockHash common.Hash `json:"blockHash,omitempty"`
|
||||
BlockNumber *hexutil.Big `json:"blockNumber,omitempty"`
|
||||
TransactionIndex hexutil.Uint `json:"transactionIndex"`
|
||||
@@ -39,6 +40,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
|
||||
enc.TxHash = r.TxHash
|
||||
enc.ContractAddress = r.ContractAddress
|
||||
enc.GasUsed = hexutil.Uint64(r.GasUsed)
|
||||
enc.EffectiveGasPrice = (*hexutil.Big)(r.EffectiveGasPrice)
|
||||
enc.BlockHash = r.BlockHash
|
||||
enc.BlockNumber = (*hexutil.Big)(r.BlockNumber)
|
||||
enc.TransactionIndex = hexutil.Uint(r.TransactionIndex)
|
||||
@@ -57,6 +59,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
|
||||
TxHash *common.Hash `json:"transactionHash" gencodec:"required"`
|
||||
ContractAddress *common.Address `json:"contractAddress"`
|
||||
GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"`
|
||||
EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice,omitempty"`
|
||||
BlockHash *common.Hash `json:"blockHash,omitempty"`
|
||||
BlockNumber *hexutil.Big `json:"blockNumber,omitempty"`
|
||||
TransactionIndex *hexutil.Uint `json:"transactionIndex"`
|
||||
@@ -97,6 +100,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
|
||||
return errors.New("missing required field 'gasUsed' for Receipt")
|
||||
}
|
||||
r.GasUsed = uint64(*dec.GasUsed)
|
||||
if dec.EffectiveGasPrice != nil {
|
||||
r.EffectiveGasPrice = (*big.Int)(dec.EffectiveGasPrice)
|
||||
}
|
||||
if dec.BlockHash != nil {
|
||||
r.BlockHash = *dec.BlockHash
|
||||
}
|
||||
|
||||
42
core/types/hashes.go
Normal file
42
core/types/hashes.go
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2023 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
var (
|
||||
// EmptyRootHash is the known root hash of an empty trie.
|
||||
EmptyRootHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
|
||||
// EmptyUncleHash is the known hash of the empty uncle set.
|
||||
EmptyUncleHash = rlpHash([]*Header(nil)) // 1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347
|
||||
|
||||
// EmptyCodeHash is the known hash of the empty EVM bytecode.
|
||||
EmptyCodeHash = crypto.Keccak256Hash(nil) // c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
|
||||
|
||||
// EmptyTxsHash is the known hash of the empty transaction set.
|
||||
EmptyTxsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
|
||||
// EmptyReceiptsHash is the known hash of the empty receipt set.
|
||||
EmptyReceiptsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
|
||||
// EmptyWithdrawalsHash is the known hash of the empty withdrawal set.
|
||||
EmptyWithdrawalsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||
)
|
||||
@@ -59,10 +59,10 @@ type Receipt struct {
|
||||
Logs []*Log `json:"logs" gencodec:"required"`
|
||||
|
||||
// Implementation fields: These fields are added by geth when processing a transaction.
|
||||
// They are stored in the chain database.
|
||||
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
|
||||
ContractAddress common.Address `json:"contractAddress"`
|
||||
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
|
||||
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
|
||||
ContractAddress common.Address `json:"contractAddress"`
|
||||
GasUsed uint64 `json:"gasUsed" gencodec:"required"`
|
||||
EffectiveGasPrice *big.Int `json:"effectiveGasPrice"`
|
||||
|
||||
// Inclusion information: These fields provide information about the inclusion of the
|
||||
// transaction corresponding to this receipt.
|
||||
@@ -313,7 +313,7 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
|
||||
|
||||
// DeriveFields fills the receipts with their computed fields based on consensus
|
||||
// data and contextual infos like containing block and transactions.
|
||||
func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, txs Transactions) error {
|
||||
func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, baseFee *big.Int, txs []*Transaction) error {
|
||||
signer := MakeSigner(config, new(big.Int).SetUint64(number))
|
||||
|
||||
logIndex := uint(0)
|
||||
@@ -325,6 +325,8 @@ func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, nu
|
||||
rs[i].Type = txs[i].Type()
|
||||
rs[i].TxHash = txs[i].Hash()
|
||||
|
||||
rs[i].EffectiveGasPrice = txs[i].inner.effectiveGasPrice(new(big.Int), baseFee)
|
||||
|
||||
// block location fields
|
||||
rs[i].BlockHash = hash
|
||||
rs[i].BlockNumber = new(big.Int).SetUint64(number)
|
||||
@@ -335,13 +337,17 @@ func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, nu
|
||||
// Deriving the signer is expensive, only do if it's actually needed
|
||||
from, _ := Sender(signer, txs[i])
|
||||
rs[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
|
||||
} else {
|
||||
rs[i].ContractAddress = common.Address{}
|
||||
}
|
||||
|
||||
// The used gas can be calculated based on previous r
|
||||
if i == 0 {
|
||||
rs[i].GasUsed = rs[i].CumulativeGasUsed
|
||||
} else {
|
||||
rs[i].GasUsed = rs[i].CumulativeGasUsed - rs[i-1].CumulativeGasUsed
|
||||
}
|
||||
|
||||
// The derived log fields can simply be set from the block and transaction
|
||||
for j := 0; j < len(rs[i].Logs); j++ {
|
||||
rs[i].Logs[j].BlockNumber = number
|
||||
|
||||
@@ -18,15 +18,16 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"math"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/kylelemons/godebug/diff"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -96,122 +97,177 @@ func TestDeriveFields(t *testing.T) {
|
||||
// Create a few transactions to have receipts for
|
||||
to2 := common.HexToAddress("0x2")
|
||||
to3 := common.HexToAddress("0x3")
|
||||
to4 := common.HexToAddress("0x4")
|
||||
to5 := common.HexToAddress("0x5")
|
||||
txs := Transactions{
|
||||
NewTx(&LegacyTx{
|
||||
Nonce: 1,
|
||||
Value: big.NewInt(1),
|
||||
Gas: 1,
|
||||
GasPrice: big.NewInt(1),
|
||||
GasPrice: big.NewInt(11),
|
||||
}),
|
||||
NewTx(&LegacyTx{
|
||||
To: &to2,
|
||||
Nonce: 2,
|
||||
Value: big.NewInt(2),
|
||||
Gas: 2,
|
||||
GasPrice: big.NewInt(2),
|
||||
GasPrice: big.NewInt(22),
|
||||
}),
|
||||
NewTx(&AccessListTx{
|
||||
To: &to3,
|
||||
Nonce: 3,
|
||||
Value: big.NewInt(3),
|
||||
Gas: 3,
|
||||
GasPrice: big.NewInt(3),
|
||||
GasPrice: big.NewInt(33),
|
||||
}),
|
||||
// EIP-1559 transactions.
|
||||
NewTx(&DynamicFeeTx{
|
||||
To: &to4,
|
||||
Nonce: 4,
|
||||
Value: big.NewInt(4),
|
||||
Gas: 4,
|
||||
GasTipCap: big.NewInt(44),
|
||||
GasFeeCap: big.NewInt(1045),
|
||||
}),
|
||||
NewTx(&DynamicFeeTx{
|
||||
To: &to5,
|
||||
Nonce: 5,
|
||||
Value: big.NewInt(5),
|
||||
Gas: 5,
|
||||
GasTipCap: big.NewInt(56),
|
||||
GasFeeCap: big.NewInt(1055),
|
||||
}),
|
||||
}
|
||||
|
||||
blockNumber := big.NewInt(1)
|
||||
blockHash := common.BytesToHash([]byte{0x03, 0x14})
|
||||
|
||||
// Create the corresponding receipts
|
||||
receipts := Receipts{
|
||||
&Receipt{
|
||||
Status: ReceiptStatusFailed,
|
||||
CumulativeGasUsed: 1,
|
||||
Logs: []*Log{
|
||||
{Address: common.BytesToAddress([]byte{0x11})},
|
||||
{Address: common.BytesToAddress([]byte{0x01, 0x11})},
|
||||
{
|
||||
Address: common.BytesToAddress([]byte{0x11}),
|
||||
// derived fields:
|
||||
BlockNumber: blockNumber.Uint64(),
|
||||
TxHash: txs[0].Hash(),
|
||||
TxIndex: 0,
|
||||
BlockHash: blockHash,
|
||||
Index: 0,
|
||||
},
|
||||
{
|
||||
Address: common.BytesToAddress([]byte{0x01, 0x11}),
|
||||
// derived fields:
|
||||
BlockNumber: blockNumber.Uint64(),
|
||||
TxHash: txs[0].Hash(),
|
||||
TxIndex: 0,
|
||||
BlockHash: blockHash,
|
||||
Index: 1,
|
||||
},
|
||||
},
|
||||
TxHash: txs[0].Hash(),
|
||||
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
|
||||
GasUsed: 1,
|
||||
// derived fields:
|
||||
TxHash: txs[0].Hash(),
|
||||
ContractAddress: common.HexToAddress("0x5a443704dd4b594b382c22a083e2bd3090a6fef3"),
|
||||
GasUsed: 1,
|
||||
EffectiveGasPrice: big.NewInt(11),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
TransactionIndex: 0,
|
||||
},
|
||||
&Receipt{
|
||||
PostState: common.Hash{2}.Bytes(),
|
||||
CumulativeGasUsed: 3,
|
||||
Logs: []*Log{
|
||||
{Address: common.BytesToAddress([]byte{0x22})},
|
||||
{Address: common.BytesToAddress([]byte{0x02, 0x22})},
|
||||
{
|
||||
Address: common.BytesToAddress([]byte{0x22}),
|
||||
// derived fields:
|
||||
BlockNumber: blockNumber.Uint64(),
|
||||
TxHash: txs[1].Hash(),
|
||||
TxIndex: 1,
|
||||
BlockHash: blockHash,
|
||||
Index: 2,
|
||||
},
|
||||
{
|
||||
Address: common.BytesToAddress([]byte{0x02, 0x22}),
|
||||
// derived fields:
|
||||
BlockNumber: blockNumber.Uint64(),
|
||||
TxHash: txs[1].Hash(),
|
||||
TxIndex: 1,
|
||||
BlockHash: blockHash,
|
||||
Index: 3,
|
||||
},
|
||||
},
|
||||
TxHash: txs[1].Hash(),
|
||||
ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
|
||||
GasUsed: 2,
|
||||
// derived fields:
|
||||
TxHash: txs[1].Hash(),
|
||||
GasUsed: 2,
|
||||
EffectiveGasPrice: big.NewInt(22),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
TransactionIndex: 1,
|
||||
},
|
||||
&Receipt{
|
||||
Type: AccessListTxType,
|
||||
PostState: common.Hash{3}.Bytes(),
|
||||
CumulativeGasUsed: 6,
|
||||
Logs: []*Log{
|
||||
{Address: common.BytesToAddress([]byte{0x33})},
|
||||
{Address: common.BytesToAddress([]byte{0x03, 0x33})},
|
||||
},
|
||||
TxHash: txs[2].Hash(),
|
||||
ContractAddress: common.BytesToAddress([]byte{0x03, 0x33, 0x33}),
|
||||
GasUsed: 3,
|
||||
Logs: []*Log{},
|
||||
// derived fields:
|
||||
TxHash: txs[2].Hash(),
|
||||
GasUsed: 3,
|
||||
EffectiveGasPrice: big.NewInt(33),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
TransactionIndex: 2,
|
||||
},
|
||||
&Receipt{
|
||||
Type: DynamicFeeTxType,
|
||||
PostState: common.Hash{4}.Bytes(),
|
||||
CumulativeGasUsed: 10,
|
||||
Logs: []*Log{},
|
||||
// derived fields:
|
||||
TxHash: txs[3].Hash(),
|
||||
GasUsed: 4,
|
||||
EffectiveGasPrice: big.NewInt(1044),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
TransactionIndex: 3,
|
||||
},
|
||||
&Receipt{
|
||||
Type: DynamicFeeTxType,
|
||||
PostState: common.Hash{5}.Bytes(),
|
||||
CumulativeGasUsed: 15,
|
||||
Logs: []*Log{},
|
||||
// derived fields:
|
||||
TxHash: txs[4].Hash(),
|
||||
GasUsed: 5,
|
||||
EffectiveGasPrice: big.NewInt(1055),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: blockNumber,
|
||||
TransactionIndex: 4,
|
||||
},
|
||||
}
|
||||
// Clear all the computed fields and re-derive them
|
||||
number := big.NewInt(1)
|
||||
hash := common.BytesToHash([]byte{0x03, 0x14})
|
||||
|
||||
clearComputedFieldsOnReceipts(t, receipts)
|
||||
if err := receipts.DeriveFields(params.TestChainConfig, hash, number.Uint64(), txs); err != nil {
|
||||
// Re-derive receipts.
|
||||
basefee := big.NewInt(1000)
|
||||
derivedReceipts := clearComputedFieldsOnReceipts(receipts)
|
||||
err := Receipts(derivedReceipts).DeriveFields(params.TestChainConfig, blockHash, blockNumber.Uint64(), basefee, txs)
|
||||
if err != nil {
|
||||
t.Fatalf("DeriveFields(...) = %v, want <nil>", err)
|
||||
}
|
||||
// Iterate over all the computed fields and check that they're correct
|
||||
signer := MakeSigner(params.TestChainConfig, number)
|
||||
|
||||
logIndex := uint(0)
|
||||
for i := range receipts {
|
||||
if receipts[i].Type != txs[i].Type() {
|
||||
t.Errorf("receipts[%d].Type = %d, want %d", i, receipts[i].Type, txs[i].Type())
|
||||
}
|
||||
if receipts[i].TxHash != txs[i].Hash() {
|
||||
t.Errorf("receipts[%d].TxHash = %s, want %s", i, receipts[i].TxHash.String(), txs[i].Hash().String())
|
||||
}
|
||||
if receipts[i].BlockHash != hash {
|
||||
t.Errorf("receipts[%d].BlockHash = %s, want %s", i, receipts[i].BlockHash.String(), hash.String())
|
||||
}
|
||||
if receipts[i].BlockNumber.Cmp(number) != 0 {
|
||||
t.Errorf("receipts[%c].BlockNumber = %s, want %s", i, receipts[i].BlockNumber.String(), number.String())
|
||||
}
|
||||
if receipts[i].TransactionIndex != uint(i) {
|
||||
t.Errorf("receipts[%d].TransactionIndex = %d, want %d", i, receipts[i].TransactionIndex, i)
|
||||
}
|
||||
if receipts[i].GasUsed != txs[i].Gas() {
|
||||
t.Errorf("receipts[%d].GasUsed = %d, want %d", i, receipts[i].GasUsed, txs[i].Gas())
|
||||
}
|
||||
if txs[i].To() != nil && receipts[i].ContractAddress != (common.Address{}) {
|
||||
t.Errorf("receipts[%d].ContractAddress = %s, want %s", i, receipts[i].ContractAddress.String(), (common.Address{}).String())
|
||||
}
|
||||
from, _ := Sender(signer, txs[i])
|
||||
contractAddress := crypto.CreateAddress(from, txs[i].Nonce())
|
||||
if txs[i].To() == nil && receipts[i].ContractAddress != contractAddress {
|
||||
t.Errorf("receipts[%d].ContractAddress = %s, want %s", i, receipts[i].ContractAddress.String(), contractAddress.String())
|
||||
}
|
||||
for j := range receipts[i].Logs {
|
||||
if receipts[i].Logs[j].BlockNumber != number.Uint64() {
|
||||
t.Errorf("receipts[%d].Logs[%d].BlockNumber = %d, want %d", i, j, receipts[i].Logs[j].BlockNumber, number.Uint64())
|
||||
}
|
||||
if receipts[i].Logs[j].BlockHash != hash {
|
||||
t.Errorf("receipts[%d].Logs[%d].BlockHash = %s, want %s", i, j, receipts[i].Logs[j].BlockHash.String(), hash.String())
|
||||
}
|
||||
if receipts[i].Logs[j].TxHash != txs[i].Hash() {
|
||||
t.Errorf("receipts[%d].Logs[%d].TxHash = %s, want %s", i, j, receipts[i].Logs[j].TxHash.String(), txs[i].Hash().String())
|
||||
}
|
||||
if receipts[i].Logs[j].TxIndex != uint(i) {
|
||||
t.Errorf("receipts[%d].Logs[%d].TransactionIndex = %d, want %d", i, j, receipts[i].Logs[j].TxIndex, i)
|
||||
}
|
||||
if receipts[i].Logs[j].Index != logIndex {
|
||||
t.Errorf("receipts[%d].Logs[%d].Index = %d, want %d", i, j, receipts[i].Logs[j].Index, logIndex)
|
||||
}
|
||||
logIndex++
|
||||
}
|
||||
// Check diff of receipts against derivedReceipts.
|
||||
r1, err := json.MarshalIndent(receipts, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal("error marshaling input receipts:", err)
|
||||
}
|
||||
r2, err := json.MarshalIndent(derivedReceipts, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal("error marshaling derived receipts:", err)
|
||||
}
|
||||
d := diff.Diff(string(r1), string(r2))
|
||||
if d != "" {
|
||||
t.Fatal("receipts differ:", d)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,41 +398,36 @@ func TestReceiptUnmarshalBinary(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func clearComputedFieldsOnReceipts(t *testing.T, receipts Receipts) {
|
||||
t.Helper()
|
||||
|
||||
for _, receipt := range receipts {
|
||||
clearComputedFieldsOnReceipt(t, receipt)
|
||||
func clearComputedFieldsOnReceipts(receipts []*Receipt) []*Receipt {
|
||||
r := make([]*Receipt, len(receipts))
|
||||
for i, receipt := range receipts {
|
||||
r[i] = clearComputedFieldsOnReceipt(receipt)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func clearComputedFieldsOnReceipt(t *testing.T, receipt *Receipt) {
|
||||
t.Helper()
|
||||
|
||||
receipt.TxHash = common.Hash{}
|
||||
receipt.BlockHash = common.Hash{}
|
||||
receipt.BlockNumber = big.NewInt(math.MaxUint32)
|
||||
receipt.TransactionIndex = math.MaxUint32
|
||||
receipt.ContractAddress = common.Address{}
|
||||
receipt.GasUsed = 0
|
||||
|
||||
clearComputedFieldsOnLogs(t, receipt.Logs)
|
||||
func clearComputedFieldsOnReceipt(receipt *Receipt) *Receipt {
|
||||
cpy := *receipt
|
||||
cpy.TxHash = common.Hash{0xff, 0xff, 0x11}
|
||||
cpy.BlockHash = common.Hash{0xff, 0xff, 0x22}
|
||||
cpy.BlockNumber = big.NewInt(math.MaxUint32)
|
||||
cpy.TransactionIndex = math.MaxUint32
|
||||
cpy.ContractAddress = common.Address{0xff, 0xff, 0x33}
|
||||
cpy.GasUsed = 0xffffffff
|
||||
cpy.Logs = clearComputedFieldsOnLogs(receipt.Logs)
|
||||
return &cpy
|
||||
}
|
||||
|
||||
func clearComputedFieldsOnLogs(t *testing.T, logs []*Log) {
|
||||
t.Helper()
|
||||
|
||||
for _, log := range logs {
|
||||
clearComputedFieldsOnLog(t, log)
|
||||
func clearComputedFieldsOnLogs(logs []*Log) []*Log {
|
||||
l := make([]*Log, len(logs))
|
||||
for i, log := range logs {
|
||||
cpy := *log
|
||||
cpy.BlockNumber = math.MaxUint32
|
||||
cpy.BlockHash = common.Hash{}
|
||||
cpy.TxHash = common.Hash{}
|
||||
cpy.TxIndex = math.MaxUint32
|
||||
cpy.Index = math.MaxUint32
|
||||
l[i] = &cpy
|
||||
}
|
||||
}
|
||||
|
||||
func clearComputedFieldsOnLog(t *testing.T, log *Log) {
|
||||
t.Helper()
|
||||
|
||||
log.BlockNumber = math.MaxUint32
|
||||
log.BlockHash = common.Hash{}
|
||||
log.TxHash = common.Hash{}
|
||||
log.TxIndex = math.MaxUint32
|
||||
log.Index = math.MaxUint32
|
||||
return l
|
||||
}
|
||||
|
||||
@@ -85,6 +85,14 @@ type TxData interface {
|
||||
|
||||
rawSignatureValues() (v, r, s *big.Int)
|
||||
setSignatureValues(chainID, v, r, s *big.Int)
|
||||
|
||||
// effectiveGasPrice computes the gas price paid by the transaction, given
|
||||
// the inclusion block baseFee.
|
||||
//
|
||||
// Unlike other TxData methods, the returned *big.Int should be an independent
|
||||
// copy of the computed value, i.e. callers are allowed to mutate the result.
|
||||
// Method implementations can use 'dst' to store the result.
|
||||
effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int
|
||||
}
|
||||
|
||||
// EncodeRLP implements rlp.Encoder
|
||||
@@ -581,74 +589,6 @@ func (t *TransactionsByPriceAndNonce) Pop() {
|
||||
heap.Pop(&t.heads)
|
||||
}
|
||||
|
||||
// Message is a fully derived transaction and implements core.Message
|
||||
//
|
||||
// NOTE: In a future PR this will be removed.
|
||||
type Message struct {
|
||||
to *common.Address
|
||||
from common.Address
|
||||
nonce uint64
|
||||
amount *big.Int
|
||||
gasLimit uint64
|
||||
gasPrice *big.Int
|
||||
gasFeeCap *big.Int
|
||||
gasTipCap *big.Int
|
||||
data []byte
|
||||
accessList AccessList
|
||||
isFake bool
|
||||
}
|
||||
|
||||
func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice, gasFeeCap, gasTipCap *big.Int, data []byte, accessList AccessList, isFake bool) Message {
|
||||
return Message{
|
||||
from: from,
|
||||
to: to,
|
||||
nonce: nonce,
|
||||
amount: amount,
|
||||
gasLimit: gasLimit,
|
||||
gasPrice: gasPrice,
|
||||
gasFeeCap: gasFeeCap,
|
||||
gasTipCap: gasTipCap,
|
||||
data: data,
|
||||
accessList: accessList,
|
||||
isFake: isFake,
|
||||
}
|
||||
}
|
||||
|
||||
// AsMessage returns the transaction as a core.Message.
|
||||
func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
|
||||
msg := Message{
|
||||
nonce: tx.Nonce(),
|
||||
gasLimit: tx.Gas(),
|
||||
gasPrice: new(big.Int).Set(tx.GasPrice()),
|
||||
gasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
|
||||
gasTipCap: new(big.Int).Set(tx.GasTipCap()),
|
||||
to: tx.To(),
|
||||
amount: tx.Value(),
|
||||
data: tx.Data(),
|
||||
accessList: tx.AccessList(),
|
||||
isFake: false,
|
||||
}
|
||||
// If baseFee provided, set gasPrice to effectiveGasPrice.
|
||||
if baseFee != nil {
|
||||
msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.gasTipCap, baseFee), msg.gasFeeCap)
|
||||
}
|
||||
var err error
|
||||
msg.from, err = Sender(s, tx)
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func (m Message) From() common.Address { return m.from }
|
||||
func (m Message) To() *common.Address { return m.to }
|
||||
func (m Message) GasPrice() *big.Int { return m.gasPrice }
|
||||
func (m Message) GasFeeCap() *big.Int { return m.gasFeeCap }
|
||||
func (m Message) GasTipCap() *big.Int { return m.gasTipCap }
|
||||
func (m Message) Value() *big.Int { return m.amount }
|
||||
func (m Message) Gas() uint64 { return m.gasLimit }
|
||||
func (m Message) Nonce() uint64 { return m.nonce }
|
||||
func (m Message) Data() []byte { return m.data }
|
||||
func (m Message) AccessList() AccessList { return m.accessList }
|
||||
func (m Message) IsFake() bool { return m.isFake }
|
||||
|
||||
// copyAddressPtr copies an address.
|
||||
func copyAddressPtr(a *common.Address) *common.Address {
|
||||
if a == nil {
|
||||
|
||||
@@ -106,6 +106,10 @@ func (tx *AccessListTx) value() *big.Int { return tx.Value }
|
||||
func (tx *AccessListTx) nonce() uint64 { return tx.Nonce }
|
||||
func (tx *AccessListTx) to() *common.Address { return tx.To }
|
||||
|
||||
func (tx *AccessListTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
|
||||
return dst.Set(tx.GasPrice)
|
||||
}
|
||||
|
||||
func (tx *AccessListTx) rawSignatureValues() (v, r, s *big.Int) {
|
||||
return tx.V, tx.R, tx.S
|
||||
}
|
||||
|
||||
@@ -94,6 +94,17 @@ func (tx *DynamicFeeTx) value() *big.Int { return tx.Value }
|
||||
func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce }
|
||||
func (tx *DynamicFeeTx) to() *common.Address { return tx.To }
|
||||
|
||||
func (tx *DynamicFeeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
|
||||
if baseFee == nil {
|
||||
return dst.Set(tx.GasFeeCap)
|
||||
}
|
||||
tip := dst.Sub(tx.GasFeeCap, baseFee)
|
||||
if tip.Cmp(tx.GasTipCap) > 0 {
|
||||
tip.Set(tx.GasTipCap)
|
||||
}
|
||||
return tip.Add(tip, baseFee)
|
||||
}
|
||||
|
||||
func (tx *DynamicFeeTx) rawSignatureValues() (v, r, s *big.Int) {
|
||||
return tx.V, tx.R, tx.S
|
||||
}
|
||||
|
||||
@@ -103,6 +103,10 @@ func (tx *LegacyTx) value() *big.Int { return tx.Value }
|
||||
func (tx *LegacyTx) nonce() uint64 { return tx.Nonce }
|
||||
func (tx *LegacyTx) to() *common.Address { return tx.To }
|
||||
|
||||
func (tx *LegacyTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
|
||||
return dst.Set(tx.GasPrice)
|
||||
}
|
||||
|
||||
func (tx *LegacyTx) rawSignatureValues() (v, r, s *big.Int) {
|
||||
return tx.V, tx.R, tx.S
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/crypto/bls12381"
|
||||
"github.com/ethereum/go-ethereum/crypto/bn256"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
big2 "github.com/holiman/big"
|
||||
"golang.org/x/crypto/ripemd160"
|
||||
)
|
||||
|
||||
@@ -378,9 +377,9 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) {
|
||||
}
|
||||
// Retrieve the operands and execute the exponentiation
|
||||
var (
|
||||
base = new(big2.Int).SetBytes(getData(input, 0, baseLen))
|
||||
exp = new(big2.Int).SetBytes(getData(input, baseLen, expLen))
|
||||
mod = new(big2.Int).SetBytes(getData(input, baseLen+expLen, modLen))
|
||||
base = new(big.Int).SetBytes(getData(input, 0, baseLen))
|
||||
exp = new(big.Int).SetBytes(getData(input, baseLen, expLen))
|
||||
mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen))
|
||||
v []byte
|
||||
)
|
||||
switch {
|
||||
|
||||
@@ -163,7 +163,7 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
|
||||
return params.NetSstoreDirtyGas, nil
|
||||
}
|
||||
|
||||
// Here come the EIP220 rules:
|
||||
// Here come the EIP2200 rules:
|
||||
//
|
||||
// (0.) If *gasleft* is less than or equal to 2300, fail the current call.
|
||||
// (1.) If current value equals new value (this is a no-op), SLOAD_GAS is deducted.
|
||||
|
||||
38
eth/api.go
38
eth/api.go
@@ -267,20 +267,24 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
|
||||
_, stateDb := api.eth.miner.Pending()
|
||||
return stateDb.RawDump(opts), nil
|
||||
}
|
||||
var block *types.Block
|
||||
var header *types.Header
|
||||
if blockNr == rpc.LatestBlockNumber {
|
||||
block = api.eth.blockchain.CurrentBlock()
|
||||
header = api.eth.blockchain.CurrentBlock()
|
||||
} else if blockNr == rpc.FinalizedBlockNumber {
|
||||
block = api.eth.blockchain.CurrentFinalizedBlock()
|
||||
header = api.eth.blockchain.CurrentFinalBlock()
|
||||
} else if blockNr == rpc.SafeBlockNumber {
|
||||
block = api.eth.blockchain.CurrentSafeBlock()
|
||||
header = api.eth.blockchain.CurrentSafeBlock()
|
||||
} else {
|
||||
block = api.eth.blockchain.GetBlockByNumber(uint64(blockNr))
|
||||
block := api.eth.blockchain.GetBlockByNumber(uint64(blockNr))
|
||||
if block == nil {
|
||||
return state.Dump{}, fmt.Errorf("block #%d not found", blockNr)
|
||||
}
|
||||
header = block.Header()
|
||||
}
|
||||
if block == nil {
|
||||
if header == nil {
|
||||
return state.Dump{}, fmt.Errorf("block #%d not found", blockNr)
|
||||
}
|
||||
stateDb, err := api.eth.BlockChain().StateAt(block.Root())
|
||||
stateDb, err := api.eth.BlockChain().StateAt(header.Root)
|
||||
if err != nil {
|
||||
return state.Dump{}, err
|
||||
}
|
||||
@@ -347,20 +351,24 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
|
||||
// the miner and operate on those
|
||||
_, stateDb = api.eth.miner.Pending()
|
||||
} else {
|
||||
var block *types.Block
|
||||
var header *types.Header
|
||||
if number == rpc.LatestBlockNumber {
|
||||
block = api.eth.blockchain.CurrentBlock()
|
||||
header = api.eth.blockchain.CurrentBlock()
|
||||
} else if number == rpc.FinalizedBlockNumber {
|
||||
block = api.eth.blockchain.CurrentFinalizedBlock()
|
||||
header = api.eth.blockchain.CurrentFinalBlock()
|
||||
} else if number == rpc.SafeBlockNumber {
|
||||
block = api.eth.blockchain.CurrentSafeBlock()
|
||||
header = api.eth.blockchain.CurrentSafeBlock()
|
||||
} else {
|
||||
block = api.eth.blockchain.GetBlockByNumber(uint64(number))
|
||||
block := api.eth.blockchain.GetBlockByNumber(uint64(number))
|
||||
if block == nil {
|
||||
return state.IteratorDump{}, fmt.Errorf("block #%d not found", number)
|
||||
}
|
||||
header = block.Header()
|
||||
}
|
||||
if block == nil {
|
||||
if header == nil {
|
||||
return state.IteratorDump{}, fmt.Errorf("block #%d not found", number)
|
||||
}
|
||||
stateDb, err = api.eth.BlockChain().StateAt(block.Root())
|
||||
stateDb, err = api.eth.BlockChain().StateAt(header.Root)
|
||||
if err != nil {
|
||||
return state.IteratorDump{}, err
|
||||
}
|
||||
@@ -552,7 +560,7 @@ func (api *DebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64, error
|
||||
if block == nil {
|
||||
return 0, fmt.Errorf("current block missing")
|
||||
}
|
||||
return block.NumberU64(), nil
|
||||
return block.Number.Uint64(), nil
|
||||
}
|
||||
return uint64(num.Int64()), nil
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ func (b *EthAPIBackend) ChainConfig() *params.ChainConfig {
|
||||
return b.eth.blockchain.Config()
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) CurrentBlock() *types.Block {
|
||||
func (b *EthAPIBackend) CurrentBlock() *types.Header {
|
||||
return b.eth.blockchain.CurrentBlock()
|
||||
}
|
||||
|
||||
@@ -72,19 +72,19 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb
|
||||
}
|
||||
// Otherwise resolve and return the block
|
||||
if number == rpc.LatestBlockNumber {
|
||||
return b.eth.blockchain.CurrentBlock().Header(), nil
|
||||
return b.eth.blockchain.CurrentBlock(), nil
|
||||
}
|
||||
if number == rpc.FinalizedBlockNumber {
|
||||
block := b.eth.blockchain.CurrentFinalizedBlock()
|
||||
block := b.eth.blockchain.CurrentFinalBlock()
|
||||
if block != nil {
|
||||
return block.Header(), nil
|
||||
return block, nil
|
||||
}
|
||||
return nil, errors.New("finalized block not found")
|
||||
}
|
||||
if number == rpc.SafeBlockNumber {
|
||||
block := b.eth.blockchain.CurrentSafeBlock()
|
||||
if block != nil {
|
||||
return block.Header(), nil
|
||||
return block, nil
|
||||
}
|
||||
return nil, errors.New("safe block not found")
|
||||
}
|
||||
@@ -120,13 +120,16 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
|
||||
}
|
||||
// Otherwise resolve and return the block
|
||||
if number == rpc.LatestBlockNumber {
|
||||
return b.eth.blockchain.CurrentBlock(), nil
|
||||
header := b.eth.blockchain.CurrentBlock()
|
||||
return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil
|
||||
}
|
||||
if number == rpc.FinalizedBlockNumber {
|
||||
return b.eth.blockchain.CurrentFinalizedBlock(), nil
|
||||
header := b.eth.blockchain.CurrentFinalBlock()
|
||||
return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil
|
||||
}
|
||||
if number == rpc.SafeBlockNumber {
|
||||
return b.eth.blockchain.CurrentSafeBlock(), nil
|
||||
header := b.eth.blockchain.CurrentSafeBlock()
|
||||
return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil
|
||||
}
|
||||
return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil
|
||||
}
|
||||
@@ -225,7 +228,7 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
||||
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
||||
if vmConfig == nil {
|
||||
vmConfig = b.eth.blockchain.GetVMConfig()
|
||||
}
|
||||
@@ -379,6 +382,6 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re
|
||||
return b.eth.StateAtBlock(ctx, block, reexec, base, readOnly, preferDisk)
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
||||
}
|
||||
|
||||
@@ -237,6 +237,10 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
|
||||
log.Warn("Forkchoice requested unknown head", "hash", update.HeadBlockHash)
|
||||
return engine.STATUS_SYNCING, nil
|
||||
}
|
||||
// If the finalized hash is known, we can direct the downloader to move
|
||||
// potentially more data to the freezer from the get go.
|
||||
finalized := api.remoteBlocks.get(update.FinalizedBlockHash)
|
||||
|
||||
// Header advertised via a past newPayload request. Start syncing to it.
|
||||
// Before we do however, make sure any legacy sync in switched off so we
|
||||
// don't accidentally have 2 cycles running.
|
||||
@@ -244,8 +248,16 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
|
||||
merger.ReachTTD()
|
||||
api.eth.Downloader().Cancel()
|
||||
}
|
||||
log.Info("Forkchoice requested sync to new head", "number", header.Number, "hash", header.Hash())
|
||||
if err := api.eth.Downloader().BeaconSync(api.eth.SyncMode(), header); err != nil {
|
||||
context := []interface{}{"number", header.Number, "hash", header.Hash()}
|
||||
if update.FinalizedBlockHash != (common.Hash{}) {
|
||||
if finalized == nil {
|
||||
context = append(context, []interface{}{"finalized", "unknown"}...)
|
||||
} else {
|
||||
context = append(context, []interface{}{"finalized", finalized.Number}...)
|
||||
}
|
||||
}
|
||||
log.Info("Forkchoice requested sync to new head", context...)
|
||||
if err := api.eth.Downloader().BeaconSync(api.eth.SyncMode(), header, finalized); err != nil {
|
||||
return engine.STATUS_SYNCING, err
|
||||
}
|
||||
return engine.STATUS_SYNCING, nil
|
||||
@@ -289,7 +301,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
|
||||
} else {
|
||||
// If the head block is already in our canonical chain, the beacon client is
|
||||
// probably resyncing. Ignore the update.
|
||||
log.Info("Ignoring beacon update to old head", "number", block.NumberU64(), "hash", update.HeadBlockHash, "age", common.PrettyAge(time.Unix(int64(block.Time()), 0)), "have", api.eth.BlockChain().CurrentBlock().NumberU64())
|
||||
log.Info("Ignoring beacon update to old head", "number", block.NumberU64(), "hash", update.HeadBlockHash, "age", common.PrettyAge(time.Unix(int64(block.Time()), 0)), "have", api.eth.BlockChain().CurrentBlock().Number)
|
||||
return valid(nil), nil
|
||||
}
|
||||
api.eth.SetSynced()
|
||||
@@ -310,7 +322,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
|
||||
return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("final block not in canonical chain"))
|
||||
}
|
||||
// Set the finalized block
|
||||
api.eth.BlockChain().SetFinalized(finalBlock)
|
||||
api.eth.BlockChain().SetFinalized(finalBlock.Header())
|
||||
}
|
||||
// Check if the safe block hash is in our canonical tree, if not somethings wrong
|
||||
if update.SafeBlockHash != (common.Hash{}) {
|
||||
@@ -324,7 +336,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
|
||||
return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain"))
|
||||
}
|
||||
// Set the safe block
|
||||
api.eth.BlockChain().SetSafe(safeBlock)
|
||||
api.eth.BlockChain().SetSafe(safeBlock.Header())
|
||||
}
|
||||
// If payload generation was requested, create a new block to be potentially
|
||||
// sealed by the beacon client. The payload will be requested later, and we
|
||||
@@ -448,7 +460,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData) (engine.Payloa
|
||||
block, err := engine.ExecutableDataToBlock(params)
|
||||
if err != nil {
|
||||
log.Debug("Invalid NewPayload params", "params", params, "error", err)
|
||||
return engine.PayloadStatusV1{Status: engine.INVALIDBLOCKHASH}, nil
|
||||
return engine.PayloadStatusV1{Status: engine.INVALID}, nil
|
||||
}
|
||||
// Stash away the last update to warn the user if the beacon client goes offline
|
||||
api.lastNewPayloadLock.Lock()
|
||||
@@ -785,11 +797,14 @@ func (api *ConsensusAPI) GetPayloadBodiesByHashV1(hashes []common.Hash) []*engin
|
||||
// GetPayloadBodiesByRangeV1 implements engine_getPayloadBodiesByRangeV1 which allows for retrieval of a range
|
||||
// of block bodies by the engine api.
|
||||
func (api *ConsensusAPI) GetPayloadBodiesByRangeV1(start, count hexutil.Uint64) ([]*engine.ExecutionPayloadBodyV1, error) {
|
||||
if start == 0 || count == 0 || count > 1024 {
|
||||
if start == 0 || count == 0 {
|
||||
return nil, engine.InvalidParams.With(fmt.Errorf("invalid start or count, start: %v count: %v", start, count))
|
||||
}
|
||||
if count > 1024 {
|
||||
return nil, engine.TooLargeRequest.With(fmt.Errorf("requested count too large: %v", count))
|
||||
}
|
||||
// limit count up until current
|
||||
current := api.eth.BlockChain().CurrentBlock().NumberU64()
|
||||
current := api.eth.BlockChain().CurrentBlock().Number.Uint64()
|
||||
last := uint64(start) + uint64(count) - 1
|
||||
if last > current {
|
||||
last = current
|
||||
|
||||
@@ -19,8 +19,11 @@ package catalyst
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
crand "crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -41,7 +44,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
@@ -248,8 +250,8 @@ func TestInvalidPayloadTimestamp(t *testing.T) {
|
||||
shouldErr bool
|
||||
}{
|
||||
{0, true},
|
||||
{parent.Time(), true},
|
||||
{parent.Time() - 1, true},
|
||||
{parent.Time, true},
|
||||
{parent.Time - 1, true},
|
||||
|
||||
// TODO (MariusVanDerWijden) following tests are currently broken,
|
||||
// fixed in upcoming merge-kiln-v2 pr
|
||||
@@ -262,7 +264,7 @@ func TestInvalidPayloadTimestamp(t *testing.T) {
|
||||
params := engine.PayloadAttributes{
|
||||
Timestamp: test.time,
|
||||
Random: crypto.Keccak256Hash([]byte{byte(123)}),
|
||||
SuggestedFeeRecipient: parent.Coinbase(),
|
||||
SuggestedFeeRecipient: parent.Coinbase,
|
||||
}
|
||||
fcState := engine.ForkchoiceStateV1{
|
||||
HeadBlockHash: parent.Hash(),
|
||||
@@ -319,7 +321,7 @@ func TestEth2NewBlock(t *testing.T) {
|
||||
t.Fatalf("Failed to insert block: %v", err)
|
||||
case newResp.Status != "VALID":
|
||||
t.Fatalf("Failed to insert block: %v", newResp.Status)
|
||||
case ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64()-1:
|
||||
case ethservice.BlockChain().CurrentBlock().Number.Uint64() != block.NumberU64()-1:
|
||||
t.Fatalf("Chain head shouldn't be updated")
|
||||
}
|
||||
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
|
||||
@@ -331,7 +333,7 @@ func TestEth2NewBlock(t *testing.T) {
|
||||
if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
|
||||
t.Fatalf("Failed to insert block: %v", err)
|
||||
}
|
||||
if have, want := ethservice.BlockChain().CurrentBlock().NumberU64(), block.NumberU64(); have != want {
|
||||
if have, want := ethservice.BlockChain().CurrentBlock().Number.Uint64(), block.NumberU64(); have != want {
|
||||
t.Fatalf("Chain head should be updated, have %d want %d", have, want)
|
||||
}
|
||||
checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
|
||||
@@ -341,7 +343,7 @@ func TestEth2NewBlock(t *testing.T) {
|
||||
|
||||
// Introduce fork chain
|
||||
var (
|
||||
head = ethservice.BlockChain().CurrentBlock().NumberU64()
|
||||
head = ethservice.BlockChain().CurrentBlock().Number.Uint64()
|
||||
)
|
||||
parent = preMergeBlocks[len(preMergeBlocks)-1]
|
||||
for i := 0; i < 10; i++ {
|
||||
@@ -359,7 +361,7 @@ func TestEth2NewBlock(t *testing.T) {
|
||||
if err != nil || newResp.Status != "VALID" {
|
||||
t.Fatalf("Failed to insert block: %v", err)
|
||||
}
|
||||
if ethservice.BlockChain().CurrentBlock().NumberU64() != head {
|
||||
if ethservice.BlockChain().CurrentBlock().Number.Uint64() != head {
|
||||
t.Fatalf("Chain head shouldn't be updated")
|
||||
}
|
||||
|
||||
@@ -371,7 +373,7 @@ func TestEth2NewBlock(t *testing.T) {
|
||||
if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
|
||||
t.Fatalf("Failed to insert block: %v", err)
|
||||
}
|
||||
if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
|
||||
if ethservice.BlockChain().CurrentBlock().Number.Uint64() != block.NumberU64() {
|
||||
t.Fatalf("Chain head should be updated")
|
||||
}
|
||||
parent, head = block, block.NumberU64()
|
||||
@@ -389,7 +391,7 @@ func TestEth2DeepReorg(t *testing.T) {
|
||||
var (
|
||||
api = NewConsensusAPI(ethservice, nil)
|
||||
parent = preMergeBlocks[len(preMergeBlocks)-core.TriesInMemory-1]
|
||||
head = ethservice.BlockChain().CurrentBlock().NumberU64()
|
||||
head = ethservice.BlockChain().CurrentBlock().Number.Uint64()()
|
||||
)
|
||||
if ethservice.BlockChain().HasBlockAndState(parent.Hash(), parent.NumberU64()) {
|
||||
t.Errorf("Block %d not pruned", parent.NumberU64())
|
||||
@@ -410,13 +412,13 @@ func TestEth2DeepReorg(t *testing.T) {
|
||||
if err != nil || newResp.Status != "VALID" {
|
||||
t.Fatalf("Failed to insert block: %v", err)
|
||||
}
|
||||
if ethservice.BlockChain().CurrentBlock().NumberU64() != head {
|
||||
if ethservice.BlockChain().CurrentBlock().Number.Uint64()() != head {
|
||||
t.Fatalf("Chain head shouldn't be updated")
|
||||
}
|
||||
if err := api.setHead(block.Hash()); err != nil {
|
||||
t.Fatalf("Failed to set head: %v", err)
|
||||
}
|
||||
if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
|
||||
if ethservice.BlockChain().CurrentBlock().Number.Uint64()() != block.NumberU64() {
|
||||
t.Fatalf("Chain head should be updated")
|
||||
}
|
||||
parent, head = block, block.NumberU64()
|
||||
@@ -466,25 +468,28 @@ func TestFullAPI(t *testing.T) {
|
||||
logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
||||
)
|
||||
|
||||
callback := func(parent *types.Block) {
|
||||
statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
|
||||
callback := func(parent *types.Header) {
|
||||
statedb, _ := ethservice.BlockChain().StateAt(parent.Root)
|
||||
nonce := statedb.GetNonce(testAddr)
|
||||
tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
|
||||
ethservice.TxPool().AddLocal(tx)
|
||||
}
|
||||
|
||||
setupBlocks(t, ethservice, 10, parent, callback)
|
||||
setupBlocks(t, ethservice, 10, parent, callback, nil)
|
||||
}
|
||||
|
||||
func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Block, callback func(parent *types.Block)) []*types.Block {
|
||||
func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Header, callback func(parent *types.Header), withdrawals [][]*types.Withdrawal) []*types.Header {
|
||||
api := NewConsensusAPI(ethservice)
|
||||
var blocks []*types.Block
|
||||
var blocks []*types.Header
|
||||
for i := 0; i < n; i++ {
|
||||
callback(parent)
|
||||
var w []*types.Withdrawal
|
||||
if withdrawals != nil {
|
||||
w = withdrawals[i]
|
||||
}
|
||||
|
||||
payload := getNewPayload(t, api, parent)
|
||||
|
||||
execResp, err := api.NewPayloadV1(*payload)
|
||||
payload := getNewPayload(t, api, parent, w)
|
||||
execResp, err := api.NewPayloadV2(*payload)
|
||||
if err != nil {
|
||||
t.Fatalf("can't execute payload: %v", err)
|
||||
}
|
||||
@@ -499,10 +504,10 @@ func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Bl
|
||||
if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
|
||||
t.Fatalf("Failed to insert block: %v", err)
|
||||
}
|
||||
if ethservice.BlockChain().CurrentBlock().NumberU64() != payload.Number {
|
||||
if ethservice.BlockChain().CurrentBlock().Number.Uint64() != payload.Number {
|
||||
t.Fatal("Chain head should be updated")
|
||||
}
|
||||
if ethservice.BlockChain().CurrentFinalizedBlock().NumberU64() != payload.Number-1 {
|
||||
if ethservice.BlockChain().CurrentFinalBlock().Number.Uint64() != payload.Number-1 {
|
||||
t.Fatal("Finalized block should be updated")
|
||||
}
|
||||
parent = ethservice.BlockChain().CurrentBlock()
|
||||
@@ -585,7 +590,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) {
|
||||
logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
||||
)
|
||||
for i := 0; i < 10; i++ {
|
||||
statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
|
||||
statedb, _ := ethservice.BlockChain().StateAt(parent.Root)
|
||||
tx := types.MustSignNewTx(testKey, signer, &types.LegacyTx{
|
||||
Nonce: statedb.GetNonce(testAddr),
|
||||
Value: new(big.Int),
|
||||
@@ -596,9 +601,9 @@ func TestNewPayloadOnInvalidChain(t *testing.T) {
|
||||
ethservice.TxPool().AddRemotesSync([]*types.Transaction{tx})
|
||||
var (
|
||||
params = engine.PayloadAttributes{
|
||||
Timestamp: parent.Time() + 1,
|
||||
Timestamp: parent.Time + 1,
|
||||
Random: crypto.Keccak256Hash([]byte{byte(i)}),
|
||||
SuggestedFeeRecipient: parent.Coinbase(),
|
||||
SuggestedFeeRecipient: parent.Coinbase,
|
||||
}
|
||||
fcState = engine.ForkchoiceStateV1{
|
||||
HeadBlockHash: parent.Hash(),
|
||||
@@ -645,7 +650,7 @@ func TestNewPayloadOnInvalidChain(t *testing.T) {
|
||||
if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
|
||||
t.Fatalf("Failed to insert block: %v", err)
|
||||
}
|
||||
if ethservice.BlockChain().CurrentBlock().NumberU64() != payload.Number {
|
||||
if ethservice.BlockChain().CurrentBlock().Number.Uint64() != payload.Number {
|
||||
t.Fatalf("Chain head should be updated")
|
||||
}
|
||||
parent = ethservice.BlockChain().CurrentBlock()
|
||||
@@ -676,10 +681,10 @@ func TestEmptyBlocks(t *testing.T) {
|
||||
api := NewConsensusAPI(ethservice)
|
||||
|
||||
// Setup 10 blocks on the canonical chain
|
||||
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Block) {})
|
||||
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil)
|
||||
|
||||
// (1) check LatestValidHash by sending a normal payload (P1'')
|
||||
payload := getNewPayload(t, api, commonAncestor)
|
||||
payload := getNewPayload(t, api, commonAncestor, nil)
|
||||
|
||||
status, err := api.NewPayloadV1(*payload)
|
||||
if err != nil {
|
||||
@@ -693,7 +698,7 @@ func TestEmptyBlocks(t *testing.T) {
|
||||
}
|
||||
|
||||
// (2) Now send P1' which is invalid
|
||||
payload = getNewPayload(t, api, commonAncestor)
|
||||
payload = getNewPayload(t, api, commonAncestor, nil)
|
||||
payload.GasUsed += 1
|
||||
payload = setBlockhash(payload)
|
||||
// Now latestValidHash should be the common ancestor
|
||||
@@ -711,7 +716,7 @@ func TestEmptyBlocks(t *testing.T) {
|
||||
}
|
||||
|
||||
// (3) Now send a payload with unknown parent
|
||||
payload = getNewPayload(t, api, commonAncestor)
|
||||
payload = getNewPayload(t, api, commonAncestor, nil)
|
||||
payload.ParentHash = common.Hash{1}
|
||||
payload = setBlockhash(payload)
|
||||
// Now latestValidHash should be the common ancestor
|
||||
@@ -727,11 +732,12 @@ func TestEmptyBlocks(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *engine.ExecutableData {
|
||||
func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Header, withdrawals []*types.Withdrawal) *engine.ExecutableData {
|
||||
params := engine.PayloadAttributes{
|
||||
Timestamp: parent.Time() + 1,
|
||||
Timestamp: parent.Time + 1,
|
||||
Random: crypto.Keccak256Hash([]byte{byte(1)}),
|
||||
SuggestedFeeRecipient: parent.Coinbase(),
|
||||
SuggestedFeeRecipient: parent.Coinbase,
|
||||
Withdrawals: withdrawals,
|
||||
}
|
||||
|
||||
payload, err := assembleBlock(api, parent.Hash(), ¶ms)
|
||||
@@ -799,7 +805,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
|
||||
commonAncestor := ethserviceA.BlockChain().CurrentBlock()
|
||||
|
||||
// Setup 10 blocks on the canonical chain
|
||||
setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Block) {})
|
||||
setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Header) {}, nil)
|
||||
commonAncestor = ethserviceA.BlockChain().CurrentBlock()
|
||||
|
||||
var invalidChain []*engine.ExecutableData
|
||||
@@ -808,7 +814,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
|
||||
//invalidChain = append(invalidChain, payload1)
|
||||
|
||||
// create an invalid payload2 (P2)
|
||||
payload2 := getNewPayload(t, apiA, commonAncestor)
|
||||
payload2 := getNewPayload(t, apiA, commonAncestor, nil)
|
||||
//payload2.ParentHash = payload1.BlockHash
|
||||
payload2.GasUsed += 1
|
||||
payload2 = setBlockhash(payload2)
|
||||
@@ -817,7 +823,7 @@ func TestTrickRemoteBlockCache(t *testing.T) {
|
||||
head := payload2
|
||||
// create some valid payloads on top
|
||||
for i := 0; i < 10; i++ {
|
||||
payload := getNewPayload(t, apiA, commonAncestor)
|
||||
payload := getNewPayload(t, apiA, commonAncestor, nil)
|
||||
payload.ParentHash = head.BlockHash
|
||||
payload = setBlockhash(payload)
|
||||
invalidChain = append(invalidChain, payload)
|
||||
@@ -855,17 +861,17 @@ func TestInvalidBloom(t *testing.T) {
|
||||
api := NewConsensusAPI(ethservice)
|
||||
|
||||
// Setup 10 blocks on the canonical chain
|
||||
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Block) {})
|
||||
setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Header) {}, nil)
|
||||
|
||||
// (1) check LatestValidHash by sending a normal payload (P1'')
|
||||
payload := getNewPayload(t, api, commonAncestor)
|
||||
payload := getNewPayload(t, api, commonAncestor, nil)
|
||||
payload.LogsBloom = append(payload.LogsBloom, byte(1))
|
||||
status, err := api.NewPayloadV1(*payload)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if status.Status != engine.INVALIDBLOCKHASH {
|
||||
t.Errorf("invalid status: expected VALID got: %v", status.Status)
|
||||
if status.Status != engine.INVALID {
|
||||
t.Errorf("invalid status: expected INVALID got: %v", status.Status)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -874,7 +880,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
defer n.Close()
|
||||
|
||||
genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty())
|
||||
ethservice.BlockChain().Config().TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty())
|
||||
|
||||
var (
|
||||
api = NewConsensusAPI(ethservice)
|
||||
@@ -966,7 +972,7 @@ func TestSimultaneousNewBlock(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to convert executable data to block %v", err)
|
||||
}
|
||||
if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64()-1 {
|
||||
if ethservice.BlockChain().CurrentBlock().Number.Uint64() != block.NumberU64()-1 {
|
||||
t.Fatalf("Chain head shouldn't be updated")
|
||||
}
|
||||
fcState := engine.ForkchoiceStateV1{
|
||||
@@ -997,7 +1003,7 @@ func TestSimultaneousNewBlock(t *testing.T) {
|
||||
t.Fatal(testErr)
|
||||
}
|
||||
}
|
||||
if have, want := ethservice.BlockChain().CurrentBlock().NumberU64(), block.NumberU64(); have != want {
|
||||
if have, want := ethservice.BlockChain().CurrentBlock().Number.Uint64(), block.NumberU64(); have != want {
|
||||
t.Fatalf("Chain head should be updated, have %d want %d", have, want)
|
||||
}
|
||||
parent = block
|
||||
@@ -1233,8 +1239,10 @@ func TestNilWithdrawals(t *testing.T) {
|
||||
}
|
||||
|
||||
func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
|
||||
genesis, preMergeBlocks := generateMergeChain(10, false)
|
||||
n, ethservice := startEthService(t, genesis, preMergeBlocks)
|
||||
genesis, blocks := generateMergeChain(10, true)
|
||||
n, ethservice := startEthService(t, genesis, blocks)
|
||||
// enable shanghai on the last block
|
||||
ethservice.BlockChain().Config().ShanghaiTime = &blocks[len(blocks)-1].Header().Time
|
||||
|
||||
var (
|
||||
parent = ethservice.BlockChain().CurrentBlock()
|
||||
@@ -1242,15 +1250,45 @@ func setupBodies(t *testing.T) (*node.Node, *eth.Ethereum, []*types.Block) {
|
||||
logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
||||
)
|
||||
|
||||
callback := func(parent *types.Block) {
|
||||
statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
|
||||
callback := func(parent *types.Header) {
|
||||
statedb, _ := ethservice.BlockChain().StateAt(parent.Root)
|
||||
nonce := statedb.GetNonce(testAddr)
|
||||
tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
|
||||
ethservice.TxPool().AddLocal(tx)
|
||||
}
|
||||
|
||||
postMergeBlocks := setupBlocks(t, ethservice, 10, parent, callback)
|
||||
return n, ethservice, append(preMergeBlocks, postMergeBlocks...)
|
||||
withdrawals := make([][]*types.Withdrawal, 10)
|
||||
withdrawals[0] = nil // should be filtered out by miner
|
||||
withdrawals[1] = make([]*types.Withdrawal, 0)
|
||||
for i := 2; i < len(withdrawals); i++ {
|
||||
addr := make([]byte, 20)
|
||||
crand.Read(addr)
|
||||
withdrawals[i] = []*types.Withdrawal{
|
||||
{Index: rand.Uint64(), Validator: rand.Uint64(), Amount: rand.Uint64(), Address: common.BytesToAddress(addr)},
|
||||
}
|
||||
}
|
||||
|
||||
postShanghaiHeaders := setupBlocks(t, ethservice, 10, parent, callback, withdrawals)
|
||||
postShanghaiBlocks := make([]*types.Block, len(postShanghaiHeaders))
|
||||
for i, header := range postShanghaiHeaders {
|
||||
postShanghaiBlocks[i] = ethservice.BlockChain().GetBlock(header.Hash(), header.Number.Uint64())
|
||||
}
|
||||
return n, ethservice, append(blocks, postShanghaiBlocks...)
|
||||
}
|
||||
|
||||
func allHashes(blocks []*types.Block) []common.Hash {
|
||||
var hashes []common.Hash
|
||||
for _, b := range blocks {
|
||||
hashes = append(hashes, b.Hash())
|
||||
}
|
||||
return hashes
|
||||
}
|
||||
func allBodies(blocks []*types.Block) []*types.Body {
|
||||
var bodies []*types.Body
|
||||
for _, b := range blocks {
|
||||
bodies = append(bodies, b.Body())
|
||||
}
|
||||
return bodies
|
||||
}
|
||||
|
||||
func TestGetBlockBodiesByHash(t *testing.T) {
|
||||
@@ -1292,6 +1330,11 @@ func TestGetBlockBodiesByHash(t *testing.T) {
|
||||
results: []*types.Body{blocks[0].Body(), nil, blocks[0].Body(), blocks[0].Body()},
|
||||
hashes: []common.Hash{blocks[0].Hash(), {1, 2}, blocks[0].Hash(), blocks[0].Hash()},
|
||||
},
|
||||
// all blocks
|
||||
{
|
||||
results: allBodies(blocks),
|
||||
hashes: allHashes(blocks),
|
||||
},
|
||||
}
|
||||
|
||||
for k, test := range tests {
|
||||
@@ -1360,6 +1403,12 @@ func TestGetBlockBodiesByRange(t *testing.T) {
|
||||
start: 22,
|
||||
count: 2,
|
||||
},
|
||||
// allBlocks
|
||||
{
|
||||
results: allBodies(blocks),
|
||||
start: 1,
|
||||
count: hexutil.Uint64(len(blocks)),
|
||||
},
|
||||
}
|
||||
|
||||
for k, test := range tests {
|
||||
@@ -1383,37 +1432,43 @@ func TestGetBlockBodiesByRangeInvalidParams(t *testing.T) {
|
||||
node, eth, _ := setupBodies(t)
|
||||
api := NewConsensusAPI(eth)
|
||||
defer node.Close()
|
||||
|
||||
tests := []struct {
|
||||
start hexutil.Uint64
|
||||
count hexutil.Uint64
|
||||
want *engine.EngineAPIError
|
||||
}{
|
||||
// Genesis
|
||||
{
|
||||
start: 0,
|
||||
count: 1,
|
||||
want: engine.InvalidParams,
|
||||
},
|
||||
// No block requested
|
||||
{
|
||||
start: 1,
|
||||
count: 0,
|
||||
want: engine.InvalidParams,
|
||||
},
|
||||
// Genesis & no block
|
||||
{
|
||||
start: 0,
|
||||
count: 0,
|
||||
want: engine.InvalidParams,
|
||||
},
|
||||
// More than 1024 blocks
|
||||
{
|
||||
start: 1,
|
||||
count: 1025,
|
||||
want: engine.TooLargeRequest,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
result, err := api.GetPayloadBodiesByRangeV1(test.start, test.count)
|
||||
for i, tc := range tests {
|
||||
result, err := api.GetPayloadBodiesByRangeV1(tc.start, tc.count)
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got %v", result)
|
||||
t.Fatalf("test %d: expected error, got %v", i, result)
|
||||
}
|
||||
if have, want := err.Error(), tc.want.Error(); have != want {
|
||||
t.Fatalf("test %d: have %s, want %s", i, have, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1424,15 +1479,14 @@ func equalBody(a *types.Body, b *engine.ExecutionPayloadBodyV1) bool {
|
||||
} else if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
var want []hexutil.Bytes
|
||||
for _, tx := range a.Transactions {
|
||||
data, _ := tx.MarshalBinary()
|
||||
want = append(want, hexutil.Bytes(data))
|
||||
}
|
||||
aBytes, errA := rlp.EncodeToBytes(want)
|
||||
bBytes, errB := rlp.EncodeToBytes(b.TransactionData)
|
||||
if errA != errB {
|
||||
if len(a.Transactions) != len(b.TransactionData) {
|
||||
return false
|
||||
}
|
||||
return bytes.Equal(aBytes, bBytes)
|
||||
for i, tx := range a.Transactions {
|
||||
data, _ := tx.MarshalBinary()
|
||||
if !bytes.Equal(data, b.TransactionData[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return reflect.DeepEqual(a.Withdrawals, b.Withdrawals)
|
||||
}
|
||||
|
||||
@@ -31,9 +31,12 @@ import (
|
||||
const maxTrackedPayloads = 10
|
||||
|
||||
// maxTrackedHeaders is the maximum number of executed payloads the execution
|
||||
// engine tracks before evicting old ones. Ideally we should only ever track the
|
||||
// latest one; but have a slight wiggle room for non-ideal conditions.
|
||||
const maxTrackedHeaders = 10
|
||||
// engine tracks before evicting old ones. These are tracked outside the chain
|
||||
// during initial sync to allow ForkchoiceUpdate to reference past blocks via
|
||||
// hashes only. For the sync target it would be enough to track only the latest
|
||||
// header, but snap sync also needs the latest finalized height for the ancient
|
||||
// limit.
|
||||
const maxTrackedHeaders = 96
|
||||
|
||||
// payloadQueueItem represents an id->payload tuple to store until it's retrieved
|
||||
// or evicted.
|
||||
|
||||
@@ -75,7 +75,7 @@ func (tester *FullSyncTester) Start() error {
|
||||
}
|
||||
// Trigger beacon sync with the provided block header as
|
||||
// trusted chain head.
|
||||
err := tester.api.eth.Downloader().BeaconSync(downloader.FullSync, tester.block.Header())
|
||||
err := tester.api.eth.Downloader().BeaconSync(downloader.FullSync, tester.block.Header(), nil)
|
||||
if err != nil {
|
||||
log.Info("Failed to beacon sync", "err", err)
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func (b *beaconBackfiller) suspend() *types.Header {
|
||||
|
||||
// Sync cycle was just terminated, retrieve and return the last filled header.
|
||||
// Can't use `filled` as that contains a stale value from before cancellation.
|
||||
return b.downloader.blockchain.CurrentFastBlock().Header()
|
||||
return b.downloader.blockchain.CurrentSnapBlock()
|
||||
}
|
||||
|
||||
// resume starts the downloader threads for backfilling state and chain data.
|
||||
@@ -101,7 +101,7 @@ func (b *beaconBackfiller) resume() {
|
||||
defer func() {
|
||||
b.lock.Lock()
|
||||
b.filling = false
|
||||
b.filled = b.downloader.blockchain.CurrentFastBlock().Header()
|
||||
b.filled = b.downloader.blockchain.CurrentSnapBlock()
|
||||
b.lock.Unlock()
|
||||
}()
|
||||
// If the downloader fails, report an error as in beacon chain mode there
|
||||
@@ -151,8 +151,8 @@ func (d *Downloader) SetBadBlockCallback(onBadBlock badBlockFn) {
|
||||
//
|
||||
// Internally backfilling and state sync is done the same way, but the header
|
||||
// retrieval and scheduling is replaced.
|
||||
func (d *Downloader) BeaconSync(mode SyncMode, head *types.Header) error {
|
||||
return d.beaconSync(mode, head, true)
|
||||
func (d *Downloader) BeaconSync(mode SyncMode, head *types.Header, final *types.Header) error {
|
||||
return d.beaconSync(mode, head, final, true)
|
||||
}
|
||||
|
||||
// BeaconExtend is an optimistic version of BeaconSync, where an attempt is made
|
||||
@@ -162,7 +162,7 @@ func (d *Downloader) BeaconSync(mode SyncMode, head *types.Header) error {
|
||||
// This is useful if a beacon client is feeding us large chunks of payloads to run,
|
||||
// but is not setting the head after each.
|
||||
func (d *Downloader) BeaconExtend(mode SyncMode, head *types.Header) error {
|
||||
return d.beaconSync(mode, head, false)
|
||||
return d.beaconSync(mode, head, nil, false)
|
||||
}
|
||||
|
||||
// beaconSync is the post-merge version of the chain synchronization, where the
|
||||
@@ -171,7 +171,7 @@ func (d *Downloader) BeaconExtend(mode SyncMode, head *types.Header) error {
|
||||
//
|
||||
// Internally backfilling and state sync is done the same way, but the header
|
||||
// retrieval and scheduling is replaced.
|
||||
func (d *Downloader) beaconSync(mode SyncMode, head *types.Header, force bool) error {
|
||||
func (d *Downloader) beaconSync(mode SyncMode, head *types.Header, final *types.Header, force bool) error {
|
||||
// When the downloader starts a sync cycle, it needs to be aware of the sync
|
||||
// mode to use (full, snap). To keep the skeleton chain oblivious, inject the
|
||||
// mode into the backfiller directly.
|
||||
@@ -181,7 +181,7 @@ func (d *Downloader) beaconSync(mode SyncMode, head *types.Header, force bool) e
|
||||
d.skeleton.filler.(*beaconBackfiller).setMode(mode)
|
||||
|
||||
// Signal the skeleton sync to switch to a new head, however it wants
|
||||
if err := d.skeleton.Sync(head, force); err != nil {
|
||||
if err := d.skeleton.Sync(head, final, force); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -198,16 +198,16 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
|
||||
|
||||
switch d.getMode() {
|
||||
case FullSync:
|
||||
chainHead = d.blockchain.CurrentBlock().Header()
|
||||
chainHead = d.blockchain.CurrentBlock()
|
||||
case SnapSync:
|
||||
chainHead = d.blockchain.CurrentFastBlock().Header()
|
||||
chainHead = d.blockchain.CurrentSnapBlock()
|
||||
default:
|
||||
chainHead = d.lightchain.CurrentHeader()
|
||||
}
|
||||
number := chainHead.Number.Uint64()
|
||||
|
||||
// Retrieve the skeleton bounds and ensure they are linked to the local chain
|
||||
beaconHead, beaconTail, err := d.skeleton.Bounds()
|
||||
beaconHead, beaconTail, _, err := d.skeleton.Bounds()
|
||||
if err != nil {
|
||||
// This is a programming error. The chain backfiller was called with an
|
||||
// invalid beacon sync state. Ideally we would panic here, but erroring
|
||||
@@ -272,7 +272,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
|
||||
// until sync errors or is finished.
|
||||
func (d *Downloader) fetchBeaconHeaders(from uint64) error {
|
||||
var head *types.Header
|
||||
_, tail, err := d.skeleton.Bounds()
|
||||
_, tail, _, err := d.skeleton.Bounds()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -292,7 +292,7 @@ func (d *Downloader) fetchBeaconHeaders(from uint64) error {
|
||||
for {
|
||||
// Some beacon headers might have appeared since the last cycle, make
|
||||
// sure we're always syncing to all available ones
|
||||
head, _, err = d.skeleton.Bounds()
|
||||
head, _, _, err = d.skeleton.Bounds()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -154,6 +154,11 @@ type Downloader struct {
|
||||
bodyFetchHook func([]*types.Header) // Method to call upon starting a block body fetch
|
||||
receiptFetchHook func([]*types.Header) // Method to call upon starting a receipt fetch
|
||||
chainInsertHook func([]*fetchResult) // Method to call upon inserting a chain of blocks (possibly in multiple invocations)
|
||||
|
||||
// Progress reporting metrics
|
||||
syncStartBlock uint64 // Head snap block when Geth was started
|
||||
syncStartTime time.Time // Time instance when chain sync started
|
||||
syncLogTime time.Time // Time instance when status was last reported
|
||||
}
|
||||
|
||||
// LightChain encapsulates functions required to synchronise a light chain.
|
||||
@@ -191,10 +196,10 @@ type BlockChain interface {
|
||||
GetBlockByHash(common.Hash) *types.Block
|
||||
|
||||
// CurrentBlock retrieves the head block from the local chain.
|
||||
CurrentBlock() *types.Block
|
||||
CurrentBlock() *types.Header
|
||||
|
||||
// CurrentFastBlock retrieves the head snap block from the local chain.
|
||||
CurrentFastBlock() *types.Block
|
||||
// CurrentSnapBlock retrieves the head snap block from the local chain.
|
||||
CurrentSnapBlock() *types.Header
|
||||
|
||||
// SnapSyncCommitHead directly commits the head block to a certain entity.
|
||||
SnapSyncCommitHead(common.Hash) error
|
||||
@@ -231,7 +236,9 @@ func New(checkpoint uint64, stateDb ethdb.Database, mux *event.TypeMux, chain Bl
|
||||
quitCh: make(chan struct{}),
|
||||
SnapSyncer: snap.NewSyncer(stateDb, chain.TrieDB().Scheme()),
|
||||
stateSyncStart: make(chan *stateSync),
|
||||
syncStartBlock: chain.CurrentSnapBlock().Number.Uint64(),
|
||||
}
|
||||
// Create the post-merge skeleton syncer and start the process
|
||||
dl.skeleton = newSkeleton(stateDb, dl.peers, dropPeer, newBeaconBackfiller(dl, success))
|
||||
|
||||
go dl.stateFetcher()
|
||||
@@ -254,9 +261,9 @@ func (d *Downloader) Progress() ethereum.SyncProgress {
|
||||
mode := d.getMode()
|
||||
switch {
|
||||
case d.blockchain != nil && mode == FullSync:
|
||||
current = d.blockchain.CurrentBlock().NumberU64()
|
||||
current = d.blockchain.CurrentBlock().Number.Uint64()
|
||||
case d.blockchain != nil && mode == SnapSync:
|
||||
current = d.blockchain.CurrentFastBlock().NumberU64()
|
||||
current = d.blockchain.CurrentSnapBlock().Number.Uint64()
|
||||
case d.lightchain != nil:
|
||||
current = d.lightchain.CurrentHeader().Number.Uint64()
|
||||
default:
|
||||
@@ -473,7 +480,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
|
||||
}(time.Now())
|
||||
|
||||
// Look up the sync boundaries: the common ancestor and the target block
|
||||
var latest, pivot *types.Header
|
||||
var latest, pivot, final *types.Header
|
||||
if !beaconMode {
|
||||
// In legacy mode, use the master peer to retrieve the headers from
|
||||
latest, pivot, err = d.fetchHead(p)
|
||||
@@ -482,7 +489,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
|
||||
}
|
||||
} else {
|
||||
// In beacon mode, use the skeleton chain to retrieve the headers from
|
||||
latest, _, err = d.skeleton.Bounds()
|
||||
latest, _, final, err = d.skeleton.Bounds()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -492,7 +499,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
|
||||
// Retrieve the pivot header from the skeleton chain segment but
|
||||
// fallback to local chain if it's not found in skeleton space.
|
||||
if pivot = d.skeleton.Header(number); pivot == nil {
|
||||
_, oldest, _ := d.skeleton.Bounds() // error is already checked
|
||||
_, oldest, _, _ := d.skeleton.Bounds() // error is already checked
|
||||
if number < oldest.Number.Uint64() {
|
||||
count := int(oldest.Number.Uint64() - number) // it's capped by fsMinFullBlocks
|
||||
headers := d.readHeaderRange(oldest, count)
|
||||
@@ -516,7 +523,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
|
||||
// anyway, but still need a valid pivot block to avoid some code hitting
|
||||
// nil panics on access.
|
||||
if mode == SnapSync && pivot == nil {
|
||||
pivot = d.blockchain.CurrentBlock().Header()
|
||||
pivot = d.blockchain.CurrentBlock()
|
||||
}
|
||||
height := latest.Number.Uint64()
|
||||
|
||||
@@ -560,26 +567,41 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
|
||||
d.committed = 0
|
||||
}
|
||||
if mode == SnapSync {
|
||||
// Set the ancient data limitation.
|
||||
// If we are running snap sync, all block data older than ancientLimit will be
|
||||
// written to the ancient store. More recent data will be written to the active
|
||||
// database and will wait for the freezer to migrate.
|
||||
// Set the ancient data limitation. If we are running snap sync, all block
|
||||
// data older than ancientLimit will be written to the ancient store. More
|
||||
// recent data will be written to the active database and will wait for the
|
||||
// freezer to migrate.
|
||||
//
|
||||
// If there is a checkpoint available, then calculate the ancientLimit through
|
||||
// that. Otherwise calculate the ancient limit through the advertised height
|
||||
// of the remote peer.
|
||||
// If the network is post-merge, use either the last announced finalized
|
||||
// block as the ancient limit, or if we haven't yet received one, the head-
|
||||
// a max fork ancestry limit. One quirky case if we've already passed the
|
||||
// finalized block, in which case the skeleton.Bounds will return nil and
|
||||
// we'll revert to head - 90K. That's fine, we're finishing sync anyway.
|
||||
//
|
||||
// The reason for picking checkpoint first is that a malicious peer can give us
|
||||
// a fake (very high) height, forcing the ancient limit to also be very high.
|
||||
// The peer would start to feed us valid blocks until head, resulting in all of
|
||||
// the blocks might be written into the ancient store. A following mini-reorg
|
||||
// could cause issues.
|
||||
if d.checkpoint != 0 && d.checkpoint > fullMaxForkAncestry+1 {
|
||||
d.ancientLimit = d.checkpoint
|
||||
} else if height > fullMaxForkAncestry+1 {
|
||||
d.ancientLimit = height - fullMaxForkAncestry - 1
|
||||
// For non-merged networks, if there is a checkpoint available, then calculate
|
||||
// the ancientLimit through that. Otherwise calculate the ancient limit through
|
||||
// the advertised height of the remote peer. This most is mostly a fallback for
|
||||
// legacy networks, but should eventually be droppped. TODO(karalabe).
|
||||
if beaconMode {
|
||||
// Beacon sync, use the latest finalized block as the ancient limit
|
||||
// or a reasonable height if no finalized block is yet announced.
|
||||
if final != nil {
|
||||
d.ancientLimit = final.Number.Uint64()
|
||||
} else if height > fullMaxForkAncestry+1 {
|
||||
d.ancientLimit = height - fullMaxForkAncestry - 1
|
||||
} else {
|
||||
d.ancientLimit = 0
|
||||
}
|
||||
} else {
|
||||
d.ancientLimit = 0
|
||||
// Legacy sync, use any hardcoded checkpoints or the best announcement
|
||||
// we have from the remote peer. TODO(karalabe): Drop this pathway.
|
||||
if d.checkpoint != 0 && d.checkpoint > fullMaxForkAncestry+1 {
|
||||
d.ancientLimit = d.checkpoint
|
||||
} else if height > fullMaxForkAncestry+1 {
|
||||
d.ancientLimit = height - fullMaxForkAncestry - 1
|
||||
} else {
|
||||
d.ancientLimit = 0
|
||||
}
|
||||
}
|
||||
frozen, _ := d.stateDB.Ancients() // Ignore the error here since light client can also hit here.
|
||||
|
||||
@@ -812,9 +834,9 @@ func (d *Downloader) findAncestor(p *peerConnection, remoteHeader *types.Header)
|
||||
mode := d.getMode()
|
||||
switch mode {
|
||||
case FullSync:
|
||||
localHeight = d.blockchain.CurrentBlock().NumberU64()
|
||||
localHeight = d.blockchain.CurrentBlock().Number.Uint64()
|
||||
case SnapSync:
|
||||
localHeight = d.blockchain.CurrentFastBlock().NumberU64()
|
||||
localHeight = d.blockchain.CurrentSnapBlock().Number.Uint64()
|
||||
default:
|
||||
localHeight = d.lightchain.CurrentHeader().Number.Uint64()
|
||||
}
|
||||
@@ -1152,8 +1174,8 @@ func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, head uint64) e
|
||||
if mode == LightSync {
|
||||
head = d.lightchain.CurrentHeader().Number.Uint64()
|
||||
} else {
|
||||
head = d.blockchain.CurrentFastBlock().NumberU64()
|
||||
if full := d.blockchain.CurrentBlock().NumberU64(); head < full {
|
||||
head = d.blockchain.CurrentSnapBlock().Number.Uint64()
|
||||
if full := d.blockchain.CurrentBlock().Number.Uint64(); head < full {
|
||||
head = full
|
||||
}
|
||||
}
|
||||
@@ -1267,8 +1289,8 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode
|
||||
if rollback > 0 {
|
||||
lastHeader, lastFastBlock, lastBlock := d.lightchain.CurrentHeader().Number, common.Big0, common.Big0
|
||||
if mode != LightSync {
|
||||
lastFastBlock = d.blockchain.CurrentFastBlock().Number()
|
||||
lastBlock = d.blockchain.CurrentBlock().Number()
|
||||
lastFastBlock = d.blockchain.CurrentSnapBlock().Number
|
||||
lastBlock = d.blockchain.CurrentBlock().Number
|
||||
}
|
||||
if err := d.lightchain.SetHead(rollback - 1); err != nil { // -1 to target the parent of the first uncertain block
|
||||
// We're already unwinding the stack, only print the error to make it more visible
|
||||
@@ -1276,8 +1298,8 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode
|
||||
}
|
||||
curFastBlock, curBlock := common.Big0, common.Big0
|
||||
if mode != LightSync {
|
||||
curFastBlock = d.blockchain.CurrentFastBlock().Number()
|
||||
curBlock = d.blockchain.CurrentBlock().Number()
|
||||
curFastBlock = d.blockchain.CurrentSnapBlock().Number
|
||||
curBlock = d.blockchain.CurrentBlock().Number
|
||||
}
|
||||
log.Warn("Rolled back chain segment",
|
||||
"header", fmt.Sprintf("%d->%d", lastHeader, d.lightchain.CurrentHeader().Number),
|
||||
@@ -1322,7 +1344,7 @@ func (d *Downloader) processHeaders(origin uint64, td, ttd *big.Int, beaconMode
|
||||
// R: Nothing to give
|
||||
if mode != LightSync {
|
||||
head := d.blockchain.CurrentBlock()
|
||||
if !gotHeaders && td.Cmp(d.blockchain.GetTd(head.Hash(), head.NumberU64())) > 0 {
|
||||
if !gotHeaders && td.Cmp(d.blockchain.GetTd(head.Hash(), head.Number.Uint64())) > 0 {
|
||||
return errStallingPeer
|
||||
}
|
||||
}
|
||||
@@ -1559,7 +1581,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error {
|
||||
|
||||
// In post-merge, notify the engine API of encountered bad chains
|
||||
if d.badBlock != nil {
|
||||
head, _, err := d.skeleton.Bounds()
|
||||
head, _, _, err := d.skeleton.Bounds()
|
||||
if err != nil {
|
||||
log.Error("Failed to retrieve beacon bounds for bad block reporting", "err", err)
|
||||
} else {
|
||||
@@ -1614,6 +1636,7 @@ func (d *Downloader) processSnapSyncContent() error {
|
||||
if len(results) == 0 {
|
||||
// If pivot sync is done, stop
|
||||
if oldPivot == nil {
|
||||
d.reportSnapSyncProgress(true)
|
||||
return sync.Cancel()
|
||||
}
|
||||
// If sync failed, stop
|
||||
@@ -1627,6 +1650,8 @@ func (d *Downloader) processSnapSyncContent() error {
|
||||
if d.chainInsertHook != nil {
|
||||
d.chainInsertHook(results)
|
||||
}
|
||||
d.reportSnapSyncProgress(false)
|
||||
|
||||
// If we haven't downloaded the pivot block yet, check pivot staleness
|
||||
// notifications from the header downloader
|
||||
d.pivotLock.RLock()
|
||||
@@ -1739,7 +1764,7 @@ func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *state
|
||||
}
|
||||
default:
|
||||
}
|
||||
// Retrieve the a batch of results to import
|
||||
// Retrieve the batch of results to import
|
||||
first, last := results[0].Header, results[len(results)-1].Header
|
||||
log.Debug("Inserting snap-sync blocks", "items", len(results),
|
||||
"firstnum", first.Number, "firsthash", first.Hash(),
|
||||
@@ -1820,3 +1845,56 @@ func (d *Downloader) readHeaderRange(last *types.Header, count int) []*types.Hea
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
// reportSnapSyncProgress calculates various status reports and provides it to the user.
|
||||
func (d *Downloader) reportSnapSyncProgress(force bool) {
|
||||
// Initialize the sync start time if it's the first time we're reporting
|
||||
if d.syncStartTime.IsZero() {
|
||||
d.syncStartTime = time.Now().Add(-time.Millisecond) // -1ms offset to avoid division by zero
|
||||
}
|
||||
// Don't report all the events, just occasionally
|
||||
if !force && time.Since(d.syncLogTime) < 8*time.Second {
|
||||
return
|
||||
}
|
||||
// Don't report anything until we have a meaningful progress
|
||||
var (
|
||||
headerBytes, _ = d.stateDB.AncientSize(rawdb.ChainFreezerHeaderTable)
|
||||
bodyBytes, _ = d.stateDB.AncientSize(rawdb.ChainFreezerBodiesTable)
|
||||
receiptBytes, _ = d.stateDB.AncientSize(rawdb.ChainFreezerReceiptTable)
|
||||
)
|
||||
syncedBytes := common.StorageSize(headerBytes + bodyBytes + receiptBytes)
|
||||
if syncedBytes == 0 {
|
||||
return
|
||||
}
|
||||
var (
|
||||
header = d.blockchain.CurrentHeader()
|
||||
block = d.blockchain.CurrentSnapBlock()
|
||||
)
|
||||
syncedBlocks := block.Number.Uint64() - d.syncStartBlock
|
||||
if syncedBlocks == 0 {
|
||||
return
|
||||
}
|
||||
// Retrieve the current chain head and calculate the ETA
|
||||
latest, _, _, err := d.skeleton.Bounds()
|
||||
if err != nil {
|
||||
// We're going to cheat for non-merged networks, but that's fine
|
||||
latest = d.pivotHeader
|
||||
}
|
||||
if latest == nil {
|
||||
// This should really never happen, but add some defensive code for now.
|
||||
// TODO(karalabe): Remove it eventually if we don't see it blow.
|
||||
log.Error("Nil latest block in sync progress report")
|
||||
return
|
||||
}
|
||||
var (
|
||||
left = latest.Number.Uint64() - block.Number.Uint64()
|
||||
eta = time.Since(d.syncStartTime) / time.Duration(syncedBlocks) * time.Duration(left)
|
||||
|
||||
progress = fmt.Sprintf("%.2f%%", float64(block.Number.Uint64())*100/float64(latest.Number.Uint64()))
|
||||
headers = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(header.Number.Uint64()), common.StorageSize(headerBytes).TerminalString())
|
||||
bodies = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(block.Number.Uint64()), common.StorageSize(bodyBytes).TerminalString())
|
||||
receipts = fmt.Sprintf("%v@%v", log.FormatLogfmtUint64(block.Number.Uint64()), common.StorageSize(receiptBytes).TerminalString())
|
||||
)
|
||||
log.Info("Syncing: chain download in progress", "synced", progress, "chain", syncedBytes, "headers", headers, "bodies", bodies, "receipts", receipts, "eta", common.PrettyDuration(eta))
|
||||
d.syncLogTime = time.Now()
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user