Merge branch 'ethereum:master' into rlp-review

This commit is contained in:
David Theodore 2024-05-08 08:15:20 -05:00 committed by GitHub
commit 487b80e1aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 315 additions and 178 deletions

View file

@ -15,7 +15,7 @@ jobs:
if: type = push if: type = push
os: linux os: linux
arch: amd64 arch: amd64
dist: bionic dist: noble
go: 1.22.x go: 1.22.x
env: env:
- docker - docker
@ -32,7 +32,7 @@ jobs:
if: type = push if: type = push
os: linux os: linux
arch: arm64 arch: arm64
dist: bionic dist: noble
go: 1.22.x go: 1.22.x
env: env:
- docker - docker
@ -49,21 +49,20 @@ jobs:
- stage: build - stage: build
if: type = push if: type = push
os: linux os: linux
dist: bionic dist: noble
sudo: required sudo: required
go: 1.22.x go: 1.22.x
env: env:
- azure-linux - azure-linux
git: git:
submodules: false # avoid cloning ethereum/tests submodules: false # avoid cloning ethereum/tests
addons:
apt:
packages:
- gcc-multilib
script: script:
# Build for the primary platforms that Trusty can manage # build amd64
- go run build/ci.go install -dlgo - go run build/ci.go install -dlgo
- go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
# build 386
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
- go run build/ci.go install -dlgo -arch 386 - go run build/ci.go install -dlgo -arch 386
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds - go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
@ -100,7 +99,7 @@ jobs:
- stage: build - stage: build
os: linux os: linux
arch: amd64 arch: amd64
dist: bionic dist: noble
go: 1.22.x go: 1.22.x
script: script:
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES - travis_wait 30 go run build/ci.go test $TEST_PACKAGES
@ -109,14 +108,14 @@ jobs:
if: type = pull_request if: type = pull_request
os: linux os: linux
arch: arm64 arch: arm64
dist: bionic dist: noble
go: 1.21.x go: 1.21.x
script: script:
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES - travis_wait 30 go run build/ci.go test $TEST_PACKAGES
- stage: build - stage: build
os: linux os: linux
dist: bionic dist: noble
go: 1.21.x go: 1.21.x
script: script:
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES - travis_wait 30 go run build/ci.go test $TEST_PACKAGES
@ -125,21 +124,14 @@ jobs:
- stage: build - stage: build
if: type = cron || (type = push && tag ~= /^v[0-9]/) if: type = cron || (type = push && tag ~= /^v[0-9]/)
os: linux os: linux
dist: bionic dist: noble
go: 1.22.x go: 1.22.x
env: env:
- ubuntu-ppa - ubuntu-ppa
git: git:
submodules: false # avoid cloning ethereum/tests submodules: false # avoid cloning ethereum/tests
addons: before_install:
apt: - sudo -E apt-get -yq --no-install-suggests --no-install-recommends install devscripts debhelper dput fakeroot python-bzrlib python-paramiko
packages:
- devscripts
- debhelper
- dput
- fakeroot
- python-bzrlib
- python-paramiko
script: script:
- echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts - 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>" - go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>"
@ -148,7 +140,7 @@ jobs:
- stage: build - stage: build
if: type = cron if: type = cron
os: linux os: linux
dist: bionic dist: noble
go: 1.22.x go: 1.22.x
env: env:
- azure-purge - azure-purge
@ -161,8 +153,7 @@ jobs:
- stage: build - stage: build
if: type = cron if: type = cron
os: linux os: linux
dist: bionic dist: noble
go: 1.22.x go: 1.22.x
script: script:
- travis_wait 30 go run build/ci.go test -race $TEST_PACKAGES - travis_wait 30 go run build/ci.go test -race $TEST_PACKAGES

View file

@ -5,22 +5,48 @@
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
# version:golang 1.22.2 # version:golang 1.22.3
# https://go.dev/dl/ # https://go.dev/dl/
374ea82b289ec738e968267cac59c7d5ff180f9492250254784b2044e90df5a9 go1.22.2.src.tar.gz 80648ef34f903193d72a59c0dff019f5f98ae0c9aa13ade0b0ecbff991a76f68 go1.22.3.src.tar.gz
33e7f63077b1c5bce4f1ecadd4d990cf229667c40bfb00686990c950911b7ab7 go1.22.2.darwin-amd64.tar.gz adc9f5fee89cd53d907eb542d3b269d9d8a08a66bf1ab42175450ffbb58733fb go1.22.3.aix-ppc64.tar.gz
660298be38648723e783ba0398e90431de1cb288c637880cdb124f39bd977f0d go1.22.2.darwin-arm64.tar.gz 610e48c1df4d2f852de8bc2e7fd2dc1521aac216f0c0026625db12f67f192024 go1.22.3.darwin-amd64.tar.gz
efc7162b0cad2f918ac566a923d4701feb29dc9c0ab625157d49b1cbcbba39da go1.22.2.freebsd-386.tar.gz 02abeab3f4b8981232237ebd88f0a9bad933bc9621791cd7720a9ca29eacbe9d go1.22.3.darwin-arm64.tar.gz
d753428296e6709527e291fd204700a587ffef2c0a472b21aebea11618245929 go1.22.2.freebsd-amd64.tar.gz a5b3d54905f17af2ceaf7fcfe92edee67a5bd4eccd962dd89df719ace3e0894d go1.22.3.dragonfly-amd64.tar.gz
586d9eb7fe0489ab297ad80dd06414997df487c5cf536c490ffeaa8d8f1807a7 go1.22.2.linux-386.tar.gz b9989ca87695ae93bacde6f3aa7b13cde5f3825515eb9ed9bbef014273739889 go1.22.3.freebsd-386.tar.gz
5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17 go1.22.2.linux-amd64.tar.gz 7483961fae29d7d768afd5c9c0f229354ca3263ab7119c20bc182761f87cbc74 go1.22.3.freebsd-amd64.tar.gz
36e720b2d564980c162a48c7e97da2e407dfcc4239e1e58d98082dfa2486a0c1 go1.22.2.linux-arm64.tar.gz edf1f0b8ecf68b14faeedb4f5d868a58c4777a0282bd85e5115c39c010cd0130 go1.22.3.freebsd-arm.tar.gz
9243dfafde06e1efe24d59df6701818e6786b4adfdf1191098050d6d023c5369 go1.22.2.linux-armv6l.tar.gz 572eb70e5e835fbff7d53ebf473f611d7eb458c428f8dbd98a49196883c3309e go1.22.3.freebsd-arm64.tar.gz
251a8886c5113be6490bdbb955ddee98763b49c9b1bf4c8364c02d3b482dab00 go1.22.2.linux-ppc64le.tar.gz ef94eb2b74402e436dce970584222c4e454eb3093908591149bd2ded6862b8af go1.22.3.freebsd-riscv64.tar.gz
2b39019481c28c560d65e9811a478ae10e3ef765e0f59af362031d386a71bfef go1.22.2.linux-s390x.tar.gz 3c3f498c68334cbd11f72aadfb6bcb507eb8436cebc50f437a0523cd4c5e03d1 go1.22.3.illumos-amd64.tar.gz
651753c06df037020ef4d162c5b273452e9ba976ed17ae39e66ef7ee89d8147e go1.22.2.windows-386.zip fefba30bb0d3dd1909823ee38c9f1930c3dc5337a2ac4701c2277a329a386b57 go1.22.3.linux-386.tar.gz
8e581cf330f49d3266e936521a2d8263679ef7e2fc2cbbceb85659122d883596 go1.22.2.windows-amd64.zip 8920ea521bad8f6b7bc377b4824982e011c19af27df88a815e3586ea895f1b36 go1.22.3.linux-amd64.tar.gz
ddfca5beb9a0c62254266c3090c2555d899bf3e7aa26243e7de3621108f06875 go1.22.2.windows-arm64.zip 6c33e52a5b26e7aa021b94475587fce80043a727a54ceb0eee2f9fc160646434 go1.22.3.linux-arm64.tar.gz
f2bacad20cd2b96f23a86d4826525d42b229fd431cc6d0dec61ff3bc448ef46e go1.22.3.linux-armv6l.tar.gz
41e9328340544893482b2928ae18a9a88ba18b2fdd29ac77f4d33cf1815bbdc2 go1.22.3.linux-loong64.tar.gz
cf4d5faff52e642492729eaf396968f43af179518be769075b90bc1bf650abf6 go1.22.3.linux-mips.tar.gz
3bd009fe2e3d2bfd52433a11cb210d1dfa50b11b4c347a293951efd9e36de945 go1.22.3.linux-mips64.tar.gz
5913b82a042188ef698f7f2dfd0cd0c71f0508a4739de9e41fceff3f4dc769b4 go1.22.3.linux-mips64le.tar.gz
441afebca555be5313867b4577f237c7b5c0fff4386e22e47875b9f805abbec5 go1.22.3.linux-mipsle.tar.gz
f3b53190a76f4a35283501ba6d94cbb72093be0c62ff735c6f9e586a1c983381 go1.22.3.linux-ppc64.tar.gz
04b7b05283de30dd2da20bf3114b2e22cc727938aed3148babaf35cc951051ac go1.22.3.linux-ppc64le.tar.gz
d4992d4a85696e3f1de06cefbfc2fd840c9c6695d77a0f35cfdc4e28b2121c20 go1.22.3.linux-riscv64.tar.gz
2aba796417a69be5f3ed489076bac79c1c02b36e29422712f9f3bf51da9cf2d4 go1.22.3.linux-s390x.tar.gz
d6e6113542dd9f23db899e177fe23772bac114a5ea5e8ee436b9da68628335a8 go1.22.3.netbsd-386.tar.gz
c33cee3075bd18ceefddd75bafa8efb51fbdc17b5ee74275122e7a927a237a4c go1.22.3.netbsd-amd64.tar.gz
1ab251df3c85f3b391a09565ca52fb6e1306527d72852d553e9ab74eabb4ecf8 go1.22.3.netbsd-arm.tar.gz
1d194fe53f5d82f9a612f848950d8af8cab7cb40ccc03f10c4eb1c9808ff1a0c go1.22.3.netbsd-arm64.tar.gz
91d6601727f08506e938640885d3ded784925045e3a4444fd9b4b936efe1b1e0 go1.22.3.openbsd-386.tar.gz
09d0c91ae35a4eea92615426992062ca236cc2f66444fb0b0a24cd3b13bd5297 go1.22.3.openbsd-amd64.tar.gz
338da30cc2c97b9458e0b4caa2509f67bba55d3de16fb7d31775baca82d2e3dc go1.22.3.openbsd-arm.tar.gz
53eadfabd2b7dd09a64941421afee2a2888e2a4f94f353b27919b1dad1171a21 go1.22.3.openbsd-arm64.tar.gz
8a1a2842ae8dcf2374bb05dff58074b368bb698dc9c211c794c1ff119cd9fdc7 go1.22.3.plan9-386.tar.gz
f9816d3dd9e730cad55085ea08c1f0c925720728f9c945fff59cd24d2ac2db7b go1.22.3.plan9-amd64.tar.gz
f4d3d7b17c9e1b1635fcb287b5b5ab5b60acc9db3ba6a27f2b2f5d6537a2ef95 go1.22.3.plan9-arm.tar.gz
46b7999ee94d91b21ad6940b5a3131ff6fe53ef97be9a34e582e2a3ad7263e95 go1.22.3.solaris-amd64.tar.gz
f60f63b8a0885e0d924f39fd284aee5438fe87d8c3d8545a312adf43e0d9edac go1.22.3.windows-386.zip
cab2af6951a6e2115824263f6df13ff069c47270f5788714fa1d776f7f60cb39 go1.22.3.windows-amd64.zip
40b37f4b068fc759f3a0dd61176a0f7570a4ba48bed8561c31d3967a3583981a go1.22.3.windows-arm.zip
59b76ee22b9b1c3afbf7f50e3cb4edb954d6c0d25e5e029ab5483a6804d61e71 go1.22.3.windows-arm64.zip
# version:golangci 1.55.2 # version:golangci 1.55.2
# https://github.com/golangci/golangci-lint/releases/ # https://github.com/golangci/golangci-lint/releases/

View file

@ -162,8 +162,7 @@ func TestHistoryImportAndExport(t *testing.T) {
} }
// Now import Era. // Now import Era.
freezer := t.TempDir() db2, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
db2, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View file

@ -154,12 +154,10 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
preHeaders := make([]*types.Header, len(preBlocks)) preHeaders := make([]*types.Header, len(preBlocks))
for i, block := range preBlocks { for i, block := range preBlocks {
preHeaders[i] = block.Header() preHeaders[i] = block.Header()
t.Logf("Pre-merge header: %d", block.NumberU64())
} }
postHeaders := make([]*types.Header, len(postBlocks)) postHeaders := make([]*types.Header, len(postBlocks))
for i, block := range postBlocks { for i, block := range postBlocks {
postHeaders[i] = block.Header() postHeaders[i] = block.Header()
t.Logf("Post-merge header: %d", block.NumberU64())
} }
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil) chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil)

View file

@ -100,7 +100,6 @@ const (
blockCacheLimit = 256 blockCacheLimit = 256
receiptsCacheLimit = 32 receiptsCacheLimit = 32
txLookupCacheLimit = 1024 txLookupCacheLimit = 1024
TriesInMemory = 128
// BlockChainVersion ensures that an incompatible database forces a resync from scratch. // BlockChainVersion ensures that an incompatible database forces a resync from scratch.
// //
@ -1128,7 +1127,7 @@ func (bc *BlockChain) Stop() {
if !bc.cacheConfig.TrieDirtyDisabled { if !bc.cacheConfig.TrieDirtyDisabled {
triedb := bc.triedb triedb := bc.triedb
for _, offset := range []uint64{0, 1, TriesInMemory - 1} { for _, offset := range []uint64{0, 1, state.TriesInMemory - 1} {
if number := bc.CurrentBlock().Number.Uint64(); number > offset { if number := bc.CurrentBlock().Number.Uint64(); number > offset {
recent := bc.GetBlockByNumber(number - offset) recent := bc.GetBlockByNumber(number - offset)
@ -1452,7 +1451,7 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error {
// writeBlockWithState writes block, metadata and corresponding state data to the // writeBlockWithState writes block, metadata and corresponding state data to the
// database. // database.
func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) error { func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, statedb *state.StateDB) error {
// Calculate the total difficulty of the block // Calculate the total difficulty of the block
ptd := bc.GetTd(block.ParentHash(), block.NumberU64()-1) ptd := bc.GetTd(block.ParentHash(), block.NumberU64()-1)
if ptd == nil { if ptd == nil {
@ -1469,12 +1468,12 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd) rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd)
rawdb.WriteBlock(blockBatch, block) rawdb.WriteBlock(blockBatch, block)
rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts) rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts)
rawdb.WritePreimages(blockBatch, state.Preimages()) rawdb.WritePreimages(blockBatch, statedb.Preimages())
if err := blockBatch.Write(); err != nil { if err := blockBatch.Write(); err != nil {
log.Crit("Failed to write block into disk", "err", err) log.Crit("Failed to write block into disk", "err", err)
} }
// Commit all cached state changes into underlying memory database. // Commit all cached state changes into underlying memory database.
root, err := state.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number())) root, err := statedb.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number()))
if err != nil { if err != nil {
return err return err
} }
@ -1493,7 +1492,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
// Flush limits are not considered for the first TriesInMemory blocks. // Flush limits are not considered for the first TriesInMemory blocks.
current := block.NumberU64() current := block.NumberU64()
if current <= TriesInMemory { if current <= state.TriesInMemory {
return nil return nil
} }
// If we exceeded our memory allowance, flush matured singleton nodes to disk // If we exceeded our memory allowance, flush matured singleton nodes to disk
@ -1505,7 +1504,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
bc.triedb.Cap(limit - ethdb.IdealBatchSize) bc.triedb.Cap(limit - ethdb.IdealBatchSize)
} }
// Find the next state trie we need to commit // Find the next state trie we need to commit
chosen := current - TriesInMemory chosen := current - state.TriesInMemory
flushInterval := time.Duration(bc.flushInterval.Load()) flushInterval := time.Duration(bc.flushInterval.Load())
// If we exceeded time allowance, flush an entire trie to disk // If we exceeded time allowance, flush an entire trie to disk
if bc.gcproc > flushInterval { if bc.gcproc > flushInterval {
@ -1517,8 +1516,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
} else { } else {
// If we're exceeding limits but haven't reached a large enough memory gap, // If we're exceeding limits but haven't reached a large enough memory gap,
// warn the user that the system is becoming unstable. // warn the user that the system is becoming unstable.
if chosen < bc.lastWrite+TriesInMemory && bc.gcproc >= 2*flushInterval { if chosen < bc.lastWrite+state.TriesInMemory && bc.gcproc >= 2*flushInterval {
log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", flushInterval, "optimum", float64(chosen-bc.lastWrite)/TriesInMemory) log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", flushInterval, "optimum", float64(chosen-bc.lastWrite)/state.TriesInMemory)
} }
// Flush an entire trie and restart the counters // Flush an entire trie and restart the counters
bc.triedb.Commit(header.Root, true) bc.triedb.Commit(header.Root, true)
@ -1963,7 +1962,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them
triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them
blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits)
blockInsertTimer.UpdateSince(start) blockInsertTimer.UpdateSince(start)
return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil

View file

@ -785,7 +785,7 @@ func testFastVsFullChains(t *testing.T, scheme string) {
t.Fatalf("failed to insert receipt %d: %v", n, err) t.Fatalf("failed to insert receipt %d: %v", n, err)
} }
// Freezer style fast import the chain. // Freezer style fast import the chain.
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
if err != nil { if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err) t.Fatalf("failed to create temp freezer db: %v", err)
} }
@ -875,12 +875,12 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) {
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
} }
) )
height := uint64(1024) height := uint64(64)
_, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), nil) _, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), nil)
// makeDb creates a db instance for testing. // makeDb creates a db instance for testing.
makeDb := func() ethdb.Database { makeDb := func() ethdb.Database {
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
if err != nil { if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err) t.Fatalf("failed to create temp freezer db: %v", err)
} }
@ -1712,7 +1712,7 @@ func TestTrieForkGC(t *testing.T) {
Config: params.TestChainConfig, Config: params.TestChainConfig,
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
} }
genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
// Generate a bunch of fork blocks, each side forking from the canonical chain // Generate a bunch of fork blocks, each side forking from the canonical chain
forks := make([]*types.Block, len(blocks)) forks := make([]*types.Block, len(blocks))
@ -1740,7 +1740,7 @@ func TestTrieForkGC(t *testing.T) {
} }
} }
// Dereference all the recent tries and ensure no past trie is left in // Dereference all the recent tries and ensure no past trie is left in
for i := 0; i < TriesInMemory; i++ { for i := 0; i < state.TriesInMemory; i++ {
chain.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) chain.TrieDB().Dereference(blocks[len(blocks)-1-i].Root())
chain.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) chain.TrieDB().Dereference(forks[len(blocks)-1-i].Root())
} }
@ -1764,11 +1764,11 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
} }
genDb, shared, _ := GenerateChainWithGenesis(genesis, engine, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) genDb, shared, _ := GenerateChainWithGenesis(genesis, engine, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
original, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) original, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*state.TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) })
competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*state.TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) })
// Import the shared chain and the original canonical one // Import the shared chain and the original canonical one
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
defer db.Close() defer db.Close()
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
@ -1804,7 +1804,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
} }
// In path-based trie database implementation, it will keep 128 diff + 1 disk // In path-based trie database implementation, it will keep 128 diff + 1 disk
// layers, totally 129 latest states available. In hash-based it's 128. // layers, totally 129 latest states available. In hash-based it's 128.
states := TriesInMemory states := state.TriesInMemory
if scheme == rawdb.PathScheme { if scheme == rawdb.PathScheme {
states = states + 1 states = states + 1
} }
@ -1833,7 +1833,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) {
funds = big.NewInt(1000000000) funds = big.NewInt(1000000000)
gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{address: {Balance: funds}}} gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{address: {Balance: funds}}}
) )
height := uint64(1024) height := uint64(64)
_, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), nil) _, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), nil)
// Import the chain as a ancient-first node and ensure all pointers are updated // Import the chain as a ancient-first node and ensure all pointers are updated
@ -1908,7 +1908,7 @@ func testInsertReceiptChainRollback(t *testing.T, scheme string) {
} }
// Set up a BlockChain that uses the ancient store. // Set up a BlockChain that uses the ancient store.
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
if err != nil { if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err) t.Fatalf("failed to create temp freezer db: %v", err)
} }
@ -1972,13 +1972,13 @@ func testLowDiffLongChain(t *testing.T, scheme string) {
} }
// We must use a pretty long chain to ensure that the fork doesn't overtake us // We must use a pretty long chain to ensure that the fork doesn't overtake us
// until after at least 128 blocks post tip // until after at least 128 blocks post tip
genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*TriesInMemory, func(i int, b *BlockGen) { genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*state.TriesInMemory, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{1}) b.SetCoinbase(common.Address{1})
b.OffsetTime(-9) b.OffsetTime(-9)
}) })
// Import the canonical chain // Import the canonical chain
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
defer diskdb.Close() defer diskdb.Close()
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
@ -1992,7 +1992,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) {
} }
// Generate fork chain, starting from an early block // Generate fork chain, starting from an early block
parent := blocks[10] parent := blocks[10]
fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*TriesInMemory, func(i int, b *BlockGen) { fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*state.TriesInMemory, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{2}) b.SetCoinbase(common.Address{2})
}) })
@ -2055,7 +2055,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
// Set the terminal total difficulty in the config // Set the terminal total difficulty in the config
gspec.Config.TerminalTotalDifficulty = big.NewInt(0) gspec.Config.TerminalTotalDifficulty = big.NewInt(0)
} }
genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) { genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*state.TriesInMemory, func(i int, gen *BlockGen) {
tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key) tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key)
if err != nil { if err != nil {
t.Fatalf("failed to create tx: %v", err) t.Fatalf("failed to create tx: %v", err)
@ -2070,9 +2070,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
t.Fatalf("block %d: failed to insert into chain: %v", n, err) t.Fatalf("block %d: failed to insert into chain: %v", n, err)
} }
lastPrunedIndex := len(blocks) - TriesInMemory - 1 lastPrunedIndex := len(blocks) - state.TriesInMemory - 1
lastPrunedBlock := blocks[lastPrunedIndex] lastPrunedBlock := blocks[lastPrunedIndex]
firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] firstNonPrunedBlock := blocks[len(blocks)-state.TriesInMemory]
// Verify pruning of lastPrunedBlock // Verify pruning of lastPrunedBlock
if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) {
@ -2099,7 +2099,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
// Generate fork chain, make it longer than canon // Generate fork chain, make it longer than canon
parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock
parent := blocks[parentIndex] parent := blocks[parentIndex]
fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) { fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*state.TriesInMemory, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{2}) b.SetCoinbase(common.Address{2})
if int(b.header.Number.Uint64()) >= mergeBlock { if int(b.header.Number.Uint64()) >= mergeBlock {
b.SetPoS() b.SetPoS()
@ -2190,7 +2190,7 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) {
b.OffsetTime(-9) // A higher difficulty b.OffsetTime(-9) // A higher difficulty
}) })
// Import the shared chain and the original canonical one // Import the shared chain and the original canonical one
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
if err != nil { if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err) t.Fatalf("failed to create temp freezer db: %v", err)
} }
@ -2361,7 +2361,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
} }
}) })
// Import the shared chain and the original canonical one // Import the shared chain and the original canonical one
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
if err != nil { if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err) t.Fatalf("failed to create temp freezer db: %v", err)
} }
@ -2742,7 +2742,7 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
} }
// Generate and import the canonical chain // Generate and import the canonical chain
_, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*TriesInMemory, nil) _, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, nil)
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
if err != nil { if err != nil {
@ -2755,9 +2755,9 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
} }
// In path-based trie database implementation, it will keep 128 diff + 1 disk // In path-based trie database implementation, it will keep 128 diff + 1 disk
// layers, totally 129 latest states available. In hash-based it's 128. // layers, totally 129 latest states available. In hash-based it's 128.
states := TriesInMemory states := state.TriesInMemory
if scheme == rawdb.PathScheme { if scheme == rawdb.PathScheme {
states = TriesInMemory + 1 states = state.TriesInMemory + 1
} }
lastPrunedIndex := len(blocks) - states - 1 lastPrunedIndex := len(blocks) - states - 1
lastPrunedBlock := blocks[lastPrunedIndex] lastPrunedBlock := blocks[lastPrunedIndex]
@ -3636,16 +3636,17 @@ func testSetCanonical(t *testing.T, scheme string) {
} }
signer = types.LatestSigner(gspec.Config) signer = types.LatestSigner(gspec.Config)
engine = ethash.NewFaker() engine = ethash.NewFaker()
chainLength = 10
) )
// Generate and import the canonical chain // Generate and import the canonical chain
_, canon, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) { _, canon, _ := GenerateChainWithGenesis(gspec, engine, chainLength, func(i int, gen *BlockGen) {
tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key) tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key)
if err != nil { if err != nil {
panic(err) panic(err)
} }
gen.AddTx(tx) gen.AddTx(tx)
}) })
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
defer diskdb.Close() defer diskdb.Close()
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
@ -3659,7 +3660,7 @@ func testSetCanonical(t *testing.T, scheme string) {
} }
// Generate the side chain and import them // Generate the side chain and import them
_, side, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) { _, side, _ := GenerateChainWithGenesis(gspec, engine, chainLength, func(i int, gen *BlockGen) {
tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1), params.TxGas, gen.header.BaseFee, nil), signer, key) tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1), params.TxGas, gen.header.BaseFee, nil), signer, key)
if err != nil { if err != nil {
panic(err) panic(err)
@ -3698,8 +3699,8 @@ func testSetCanonical(t *testing.T, scheme string) {
verify(side[len(side)-1]) verify(side[len(side)-1])
// Reset the chain head to original chain // Reset the chain head to original chain
chain.SetCanonical(canon[TriesInMemory-1]) chain.SetCanonical(canon[chainLength-1])
verify(canon[TriesInMemory-1]) verify(canon[chainLength-1])
} }
// TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted // TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted

View file

@ -197,10 +197,11 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
// Create the idle freezer instance. If the given ancient directory is empty, // Create the idle freezer instance. If the given ancient directory is empty,
// in-memory chain freezer is used (e.g. dev mode); otherwise the regular // in-memory chain freezer is used (e.g. dev mode); otherwise the regular
// file-based freezer is created. // file-based freezer is created.
if ancient != "" { chainFreezerDir := ancient
ancient = resolveChainFreezerDir(ancient) if chainFreezerDir != "" {
chainFreezerDir = resolveChainFreezerDir(chainFreezerDir)
} }
frdb, err := newChainFreezer(ancient, namespace, readonly) frdb, err := newChainFreezer(chainFreezerDir, namespace, readonly)
if err != nil { if err != nil {
printChainMetadata(db) printChainMetadata(db)
return nil, err return nil, err

View file

@ -403,6 +403,9 @@ func (s *stateObject) updateRoot() {
// commit obtains a set of dirty storage trie nodes and updates the account data. // commit obtains a set of dirty storage trie nodes and updates the account data.
// The returned set can be nil if nothing to commit. This function assumes all // The returned set can be nil if nothing to commit. This function assumes all
// storage mutations have already been flushed into trie by updateRoot. // storage mutations have already been flushed into trie by updateRoot.
//
// Note, commit may run concurrently across all the state objects. Do not assume
// thread-safe access to the statedb.
func (s *stateObject) commit() (*trienode.NodeSet, error) { func (s *stateObject) commit() (*trienode.NodeSet, error) {
// Short circuit if trie is not even loaded, don't bother with committing anything // Short circuit if trie is not even loaded, don't bother with committing anything
if s.trie == nil { if s.trie == nil {

View file

@ -23,6 +23,7 @@ import (
"math/big" "math/big"
"slices" "slices"
"sort" "sort"
"sync"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -37,8 +38,12 @@ import (
"github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/trie/triestate" "github.com/ethereum/go-ethereum/trie/triestate"
"github.com/holiman/uint256" "github.com/holiman/uint256"
"golang.org/x/sync/errgroup"
) )
// TriesInMemory represents the number of layers that are kept in RAM.
const TriesInMemory = 128
type revision struct { type revision struct {
id int id int
journalIndex int journalIndex int
@ -1146,66 +1151,108 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
storageTrieNodesUpdated int storageTrieNodesUpdated int
storageTrieNodesDeleted int storageTrieNodesDeleted int
nodes = trienode.NewMergedNodeSet() nodes = trienode.NewMergedNodeSet()
codeWriter = s.db.DiskDB().NewBatch()
) )
// Handle all state deletions first // Handle all state deletions first
if err := s.handleDestruction(nodes); err != nil { if err := s.handleDestruction(nodes); err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
// Handle all state updates afterwards // Handle all state updates afterwards, concurrently to one another to shave
// off some milliseconds from the commit operation. Also accumulate the code
// writes to run in parallel with the computations.
start := time.Now() start := time.Now()
var (
code = s.db.DiskDB().NewBatch()
lock sync.Mutex
root common.Hash
workers errgroup.Group
)
// Schedule the account trie first since that will be the biggest, so give
// it the most time to crunch.
//
// TODO(karalabe): This account trie commit is *very* heavy. 5-6ms at chain
// heads, which seems excessive given that it doesn't do hashing, it just
// shuffles some data. For comparison, the *hashing* at chain head is 2-3ms.
// We need to investigate what's happening as it seems something's wonky.
// Obviously it's not an end of the world issue, just something the original
// code didn't anticipate for.
workers.Go(func() error {
// Write the account trie changes, measuring the amount of wasted time
newroot, set, err := s.trie.Commit(true)
if err != nil {
return err
}
root = newroot
// Merge the dirty nodes of account trie into global set
lock.Lock()
defer lock.Unlock()
if set != nil {
if err = nodes.Merge(set); err != nil {
return err
}
accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size()
}
s.AccountCommits = time.Since(start)
return nil
})
// Schedule each of the storage tries that need to be updated, so they can
// run concurrently to one another.
//
// TODO(karalabe): Experimentally, the account commit takes approximately the
// same time as all the storage commits combined, so we could maybe only have
// 2 threads in total. But that kind of depends on the account commit being
// more expensive than it should be, so let's fix that and revisit this todo.
for addr, op := range s.mutations { for addr, op := range s.mutations {
if op.isDelete() { if op.isDelete() {
continue continue
} }
obj := s.stateObjects[addr]
// Write any contract code associated with the state object // Write any contract code associated with the state object
obj := s.stateObjects[addr]
if obj.code != nil && obj.dirtyCode { if obj.code != nil && obj.dirtyCode {
rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code) rawdb.WriteCode(code, common.BytesToHash(obj.CodeHash()), obj.code)
obj.dirtyCode = false obj.dirtyCode = false
} }
// Run the storage updates concurrently to one another
workers.Go(func() error {
// Write any storage changes in the state object to its storage trie // Write any storage changes in the state object to its storage trie
set, err := obj.commit() set, err := obj.commit()
if err != nil { if err != nil {
return common.Hash{}, err return err
} }
// Merge the dirty nodes of storage trie into global set. It is possible // Merge the dirty nodes of storage trie into global set. It is possible
// that the account was destructed and then resurrected in the same block. // that the account was destructed and then resurrected in the same block.
// In this case, the node set is shared by both accounts. // In this case, the node set is shared by both accounts.
lock.Lock()
defer lock.Unlock()
if set != nil { if set != nil {
if err := nodes.Merge(set); err != nil { if err = nodes.Merge(set); err != nil {
return common.Hash{}, err return err
} }
updates, deleted := set.Size() updates, deleted := set.Size()
storageTrieNodesUpdated += updates storageTrieNodesUpdated += updates
storageTrieNodesDeleted += deleted storageTrieNodesDeleted += deleted
} }
s.StorageCommits = time.Since(start) // overwrite with the longest storage commit runtime
return nil
})
} }
s.StorageCommits += time.Since(start) // Schedule the code commits to run concurrently too. This shouldn't really
// take much since we don't often commit code, but since it's disk access,
if codeWriter.ValueSize() > 0 { // it's always yolo.
if err := codeWriter.Write(); err != nil { workers.Go(func() error {
if code.ValueSize() > 0 {
if err := code.Write(); err != nil {
log.Crit("Failed to commit dirty codes", "error", err) log.Crit("Failed to commit dirty codes", "error", err)
} }
} }
// Write the account trie changes, measuring the amount of wasted time return nil
start = time.Now() })
// Wait for everything to finish and update the metrics
root, set, err := s.trie.Commit(true) if err := workers.Wait(); err != nil {
if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
// Merge the dirty nodes of account trie into global set
if set != nil {
if err := nodes.Merge(set); err != nil {
return common.Hash{}, err
}
accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size()
}
// Report the commit metrics
s.AccountCommits += time.Since(start)
accountUpdatedMeter.Mark(int64(s.AccountUpdated)) accountUpdatedMeter.Mark(int64(s.AccountUpdated))
storageUpdatedMeter.Mark(int64(s.StorageUpdated)) storageUpdatedMeter.Mark(int64(s.StorageUpdated))
accountDeletedMeter.Mark(int64(s.AccountDeleted)) accountDeletedMeter.Mark(int64(s.AccountDeleted))
@ -1225,12 +1272,12 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
if err := s.snaps.Update(root, parent, s.convertAccountSet(s.stateObjectsDestruct), s.accounts, s.storages); err != nil { if err := s.snaps.Update(root, parent, s.convertAccountSet(s.stateObjectsDestruct), s.accounts, s.storages); err != nil {
log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err) log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err)
} }
// Keep 128 diff layers in the memory, persistent layer is 129th. // Keep TriesInMemory diff layers in the memory, persistent layer is 129th.
// - head layer is paired with HEAD state // - head layer is paired with HEAD state
// - head-1 layer is paired with HEAD-1 state // - head-1 layer is paired with HEAD-1 state
// - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state // - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state
if err := s.snaps.Cap(root, 128); err != nil { if err := s.snaps.Cap(root, TriesInMemory); err != nil {
log.Warn("Failed to cap snapshot tree", "root", root, "layers", 128, "err", err) log.Warn("Failed to cap snapshot tree", "root", root, "layers", TriesInMemory, "err", err)
} }
} }
s.SnapshotCommits += time.Since(start) s.SnapshotCommits += time.Since(start)

View file

@ -186,6 +186,13 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
// contract. This method is exported to be used in tests. // contract. This method is exported to be used in tests.
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil {
vmenv.Config.Tracer.OnSystemCallStart()
}
if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallEnd != nil {
defer vmenv.Config.Tracer.OnSystemCallEnd()
}
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with // If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
// the new root // the new root
msg := &Message{ msg := &Message{

View file

@ -4,6 +4,15 @@ All notable changes to the tracing interface will be documented in this file.
## [Unreleased] ## [Unreleased]
There have been minor backwards-compatible changes to the tracing interface to explicitly mark the execution of **system** contracts. As of now the only system call updates the parent beacon block root as per [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788). Other system calls are being considered for the future hardfork.
### New methods
- `OnSystemCallStart()`: This hook is called when EVM starts processing a system call. Note system calls happen outside the scope of a transaction. This event will be followed by normal EVM execution events.
- `OnSystemCallEnd()`: This hook is called when EVM finishes processing a system call.
## [v1.14.0]
There has been a major breaking change in the tracing interface for custom native tracers. JS and built-in tracers are not affected by this change and tracing API methods may be used as before. This overhaul has been done as part of the new live tracing feature ([#29189](https://github.com/ethereum/go-ethereum/pull/29189)). To learn more about live tracing please refer to the [docs](https://geth.ethereum.org/docs/developers/evm-tracing/live-tracing). There has been a major breaking change in the tracing interface for custom native tracers. JS and built-in tracers are not affected by this change and tracing API methods may be used as before. This overhaul has been done as part of the new live tracing feature ([#29189](https://github.com/ethereum/go-ethereum/pull/29189)). To learn more about live tracing please refer to the [docs](https://geth.ethereum.org/docs/developers/evm-tracing/live-tracing).
**The `EVMLogger` interface which the tracers implemented has been removed.** It has been replaced by a new struct `tracing.Hooks`. `Hooks` keeps pointers to event listening functions. Internally the EVM will use these function pointers to emit events and can skip an event if the tracer has opted not to implement it. In fact this is the main reason for this change of approach. Another benefit is the ease of adding new hooks in future, and dynamically assigning event receivers. **The `EVMLogger` interface which the tracers implemented has been removed.** It has been replaced by a new struct `tracing.Hooks`. `Hooks` keeps pointers to event listening functions. Internally the EVM will use these function pointers to emit events and can skip an event if the tracer has opted not to implement it. In fact this is the main reason for this change of approach. Another benefit is the ease of adding new hooks in future, and dynamically assigning event receivers.
@ -66,4 +75,5 @@ The hooks `CaptureStart` and `CaptureEnd` have been removed. These hooks signale
- `CaptureState` -> `OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error)`. `op` is of type `byte` which can be cast to `vm.OpCode` when necessary. A `*vm.ScopeContext` is not passed anymore. It is replaced by `tracing.OpContext` which offers access to the memory, stack and current contract. - `CaptureState` -> `OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error)`. `op` is of type `byte` which can be cast to `vm.OpCode` when necessary. A `*vm.ScopeContext` is not passed anymore. It is replaced by `tracing.OpContext` which offers access to the memory, stack and current contract.
- `CaptureFault` -> `OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error)`. Similar to above. - `CaptureFault` -> `OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error)`. Similar to above.
[unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.13.14...master [unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.14.0...master
[v1.14.0]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.0

View file

@ -81,6 +81,10 @@ type (
TxEndHook = func(receipt *types.Receipt, err error) TxEndHook = func(receipt *types.Receipt, err error)
// EnterHook is invoked when the processing of a message starts. // EnterHook is invoked when the processing of a message starts.
//
// Take note that EnterHook, when in the context of a live tracer, can be invoked
// outside of the `OnTxStart` and `OnTxEnd` hooks when dealing with system calls,
// see [OnSystemCallStartHook] and [OnSystemCallEndHook] for more information.
EnterHook = func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) EnterHook = func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
// ExitHook is invoked when the processing of a message ends. // ExitHook is invoked when the processing of a message ends.
@ -89,6 +93,10 @@ type (
// ran out of gas when attempting to persist the code to database did not // ran out of gas when attempting to persist the code to database did not
// count as a call failure and did not cause a revert of the call. This will // count as a call failure and did not cause a revert of the call. This will
// be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`. // be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`.
//
// Take note that ExitHook, when in the context of a live tracer, can be invoked
// outside of the `OnTxStart` and `OnTxEnd` hooks when dealing with system calls,
// see [OnSystemCallStartHook] and [OnSystemCallEndHook] for more information.
ExitHook = func(depth int, output []byte, gasUsed uint64, err error, reverted bool) ExitHook = func(depth int, output []byte, gasUsed uint64, err error, reverted bool)
// OpcodeHook is invoked just prior to the execution of an opcode. // OpcodeHook is invoked just prior to the execution of an opcode.
@ -125,6 +133,22 @@ type (
// GenesisBlockHook is called when the genesis block is being processed. // GenesisBlockHook is called when the genesis block is being processed.
GenesisBlockHook = func(genesis *types.Block, alloc types.GenesisAlloc) GenesisBlockHook = func(genesis *types.Block, alloc types.GenesisAlloc)
// OnSystemCallStartHook is called when a system call is about to be executed. Today,
// this hook is invoked when the EIP-4788 system call is about to be executed to set the
// beacon block root.
//
// After this hook, the EVM call tracing will happened as usual so you will receive a `OnEnter/OnExit`
// as well as state hooks between this hook and the `OnSystemCallEndHook`.
//
// Note that system call happens outside normal transaction execution, so the `OnTxStart/OnTxEnd` hooks
// will not be invoked.
OnSystemCallStartHook = func()
// OnSystemCallEndHook is called when a system call has finished executing. Today,
// this hook is invoked when the EIP-4788 system call is about to be executed to set the
// beacon block root.
OnSystemCallEndHook = func()
/* /*
- State events - - State events -
*/ */
@ -161,6 +185,8 @@ type Hooks struct {
OnBlockEnd BlockEndHook OnBlockEnd BlockEndHook
OnSkippedBlock SkippedBlockHook OnSkippedBlock SkippedBlockHook
OnGenesisBlock GenesisBlockHook OnGenesisBlock GenesisBlockHook
OnSystemCallStart OnSystemCallStartHook
OnSystemCallEnd OnSystemCallEndHook
// State events // State events
OnBalanceChange BalanceChangeHook OnBalanceChange BalanceChangeHook
OnNonceChange NonceChangeHook OnNonceChange NonceChangeHook

View file

@ -18,7 +18,6 @@ package core
import ( import (
"math/big" "math/big"
"os"
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -211,8 +210,7 @@ func TestTxIndexer(t *testing.T) {
}, },
} }
for _, c := range cases { for _, c := range cases {
frdir := t.TempDir() db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0)) rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0))
// Index the initial blocks from ancient store // Index the initial blocks from ancient store
@ -238,6 +236,5 @@ func TestTxIndexer(t *testing.T) {
verify(db, 0, indexer) verify(db, 0, indexer)
db.Close() db.Close()
os.RemoveAll(frdir)
} }
} }

View file

@ -1123,9 +1123,6 @@ func (c *bls12381MapG1) Run(input []byte) ([]byte, error) {
// Compute mapping // Compute mapping
r := bls12381.MapToG1(fe) r := bls12381.MapToG1(fe)
if err != nil {
return nil, err
}
// Encode the G1 point to 128 bytes // Encode the G1 point to 128 bytes
return encodePointG1(&r), nil return encodePointG1(&r), nil
@ -1159,9 +1156,6 @@ func (c *bls12381MapG2) Run(input []byte) ([]byte, error) {
// Compute mapping // Compute mapping
r := bls12381.MapToG2(bls12381.E2{A0: c0, A1: c1}) r := bls12381.MapToG2(bls12381.E2{A0: c0, A1: c1})
if err != nil {
return nil, err
}
// Encode the G2 point to 256 bytes // Encode the G2 point to 256 bytes
return encodePointG2(&r), nil return encodePointG2(&r), nil

View file

@ -19,7 +19,6 @@ package downloader
import ( import (
"fmt" "fmt"
"math/big" "math/big"
"os"
"sync" "sync"
"sync/atomic" "sync/atomic"
"testing" "testing"
@ -43,7 +42,6 @@ import (
// downloadTester is a test simulator for mocking out local block chain. // downloadTester is a test simulator for mocking out local block chain.
type downloadTester struct { type downloadTester struct {
freezer string
chain *core.BlockChain chain *core.BlockChain
downloader *Downloader downloader *Downloader
@ -58,8 +56,7 @@ func newTester(t *testing.T) *downloadTester {
// newTesterWithNotification creates a new downloader test mocker. // newTesterWithNotification creates a new downloader test mocker.
func newTesterWithNotification(t *testing.T, success func()) *downloadTester { func newTesterWithNotification(t *testing.T, success func()) *downloadTester {
freezer := t.TempDir() db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -76,7 +73,6 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester {
panic(err) panic(err)
} }
tester := &downloadTester{ tester := &downloadTester{
freezer: freezer,
chain: chain, chain: chain,
peers: make(map[string]*downloadTesterPeer), peers: make(map[string]*downloadTesterPeer),
} }
@ -89,8 +85,6 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester {
func (dl *downloadTester) terminate() { func (dl *downloadTester) terminate() {
dl.downloader.Terminate() dl.downloader.Terminate()
dl.chain.Stop() dl.chain.Stop()
os.RemoveAll(dl.freezer)
} }
// newPeer registers a new block download source into the downloader. // newPeer registers a new block download source into the downloader.

View file

@ -80,6 +80,16 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin
} }
available.Sub(available, call.Value) available.Sub(available, call.Value)
} }
if opts.Config.IsCancun(opts.Header.Number, opts.Header.Time) && len(call.BlobHashes) > 0 {
blobGasPerBlob := new(big.Int).SetInt64(params.BlobTxBlobGasPerBlob)
blobBalanceUsage := new(big.Int).SetInt64(int64(len(call.BlobHashes)))
blobBalanceUsage.Mul(blobBalanceUsage, blobGasPerBlob)
blobBalanceUsage.Mul(blobBalanceUsage, call.BlobGasFeeCap)
if blobBalanceUsage.Cmp(available) >= 0 {
return 0, nil, core.ErrInsufficientFunds
}
available.Sub(available, blobBalanceUsage)
}
allowance := new(big.Int).Div(available, feeCap) allowance := new(big.Int).Div(available, feeCap)
// If the allowance is larger than maximum uint64, skip checking // If the allowance is larger than maximum uint64, skip checking

View file

@ -44,6 +44,7 @@ const (
// maxBlockFetchers is the max number of goroutines to spin up to pull blocks // maxBlockFetchers is the max number of goroutines to spin up to pull blocks
// for the fee history calculation (mostly relevant for LES). // for the fee history calculation (mostly relevant for LES).
maxBlockFetchers = 4 maxBlockFetchers = 4
maxQueryLimit = 100
) )
// blockFees represents a single block for processing // blockFees represents a single block for processing
@ -240,6 +241,9 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL
if len(rewardPercentiles) != 0 { if len(rewardPercentiles) != 0 {
maxFeeHistory = oracle.maxBlockHistory maxFeeHistory = oracle.maxBlockHistory
} }
if len(rewardPercentiles) > maxQueryLimit {
return common.Big0, nil, nil, nil, nil, nil, fmt.Errorf("%w: over the query limit %d", errInvalidPercentile, maxQueryLimit)
}
if blocks > maxFeeHistory { if blocks > maxFeeHistory {
log.Warn("Sanitizing fee history length", "requested", blocks, "truncated", maxFeeHistory) log.Warn("Sanitizing fee history length", "requested", blocks, "truncated", maxFeeHistory)
blocks = maxFeeHistory blocks = maxFeeHistory

View file

@ -240,19 +240,19 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e
} }
db.db = innerDB db.db = innerDB
db.compTimeMeter = metrics.NewRegisteredMeter(namespace+"compact/time", nil) db.compTimeMeter = metrics.GetOrRegisterMeter(namespace+"compact/time", nil)
db.compReadMeter = metrics.NewRegisteredMeter(namespace+"compact/input", nil) db.compReadMeter = metrics.GetOrRegisterMeter(namespace+"compact/input", nil)
db.compWriteMeter = metrics.NewRegisteredMeter(namespace+"compact/output", nil) db.compWriteMeter = metrics.GetOrRegisterMeter(namespace+"compact/output", nil)
db.diskSizeGauge = metrics.NewRegisteredGauge(namespace+"disk/size", nil) db.diskSizeGauge = metrics.GetOrRegisterGauge(namespace+"disk/size", nil)
db.diskReadMeter = metrics.NewRegisteredMeter(namespace+"disk/read", nil) db.diskReadMeter = metrics.GetOrRegisterMeter(namespace+"disk/read", nil)
db.diskWriteMeter = metrics.NewRegisteredMeter(namespace+"disk/write", nil) db.diskWriteMeter = metrics.GetOrRegisterMeter(namespace+"disk/write", nil)
db.writeDelayMeter = metrics.NewRegisteredMeter(namespace+"compact/writedelay/duration", nil) db.writeDelayMeter = metrics.GetOrRegisterMeter(namespace+"compact/writedelay/duration", nil)
db.writeDelayNMeter = metrics.NewRegisteredMeter(namespace+"compact/writedelay/counter", nil) db.writeDelayNMeter = metrics.GetOrRegisterMeter(namespace+"compact/writedelay/counter", nil)
db.memCompGauge = metrics.NewRegisteredGauge(namespace+"compact/memory", nil) db.memCompGauge = metrics.GetOrRegisterGauge(namespace+"compact/memory", nil)
db.level0CompGauge = metrics.NewRegisteredGauge(namespace+"compact/level0", nil) db.level0CompGauge = metrics.GetOrRegisterGauge(namespace+"compact/level0", nil)
db.nonlevel0CompGauge = metrics.NewRegisteredGauge(namespace+"compact/nonlevel0", nil) db.nonlevel0CompGauge = metrics.GetOrRegisterGauge(namespace+"compact/nonlevel0", nil)
db.seekCompGauge = metrics.NewRegisteredGauge(namespace+"compact/seek", nil) db.seekCompGauge = metrics.GetOrRegisterGauge(namespace+"compact/seek", nil)
db.manualMemAllocGauge = metrics.NewRegisteredGauge(namespace+"memory/manualalloc", nil) db.manualMemAllocGauge = metrics.GetOrRegisterGauge(namespace+"memory/manualalloc", nil)
// Start up the metrics gathering and return // Start up the metrics gathering and return
go db.meter(metricsGatheringInterval, namespace) go db.meter(metricsGatheringInterval, namespace)
@ -543,7 +543,7 @@ func (d *Database) meter(refresh time.Duration, namespace string) {
for i, level := range stats.Levels { for i, level := range stats.Levels {
// Append metrics for additional layers // Append metrics for additional layers
if i >= len(d.levelsGauge) { if i >= len(d.levelsGauge) {
d.levelsGauge = append(d.levelsGauge, metrics.NewRegisteredGauge(namespace+fmt.Sprintf("tables/level%v", i), nil)) d.levelsGauge = append(d.levelsGauge, metrics.GetOrRegisterGauge(namespace+fmt.Sprintf("tables/level%v", i), nil))
} }
d.levelsGauge[i].Update(level.NumFiles) d.levelsGauge[i].Update(level.NumFiles)
} }

View file

@ -30,6 +30,7 @@ import (
"testing" "testing"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -283,9 +284,38 @@ func TestDecodeErrorsV5(t *testing.T) {
b = make([]byte, 63) b = make([]byte, 63)
net.nodeA.expectDecodeErr(t, errInvalidHeader, b) net.nodeA.expectDecodeErr(t, errInvalidHeader, b)
// TODO some more tests would be nice :) t.Run("invalid-handshake-datasize", func(t *testing.T) {
// - check invalid authdata sizes requiredNumber := 108
// - check invalid handshake data sizes
testDataFile := filepath.Join("testdata", "v5.1-ping-handshake"+".txt")
enc := hexFile(testDataFile)
//delete some byte from handshake to make it invalid
enc = enc[:len(enc)-requiredNumber]
net.nodeB.expectDecodeErr(t, errMsgTooShort, enc)
})
t.Run("invalid-auth-datasize", func(t *testing.T) {
testPacket := []byte{}
testDataFiles := []string{"v5.1-whoareyou", "v5.1-ping-handshake"}
for counter, name := range testDataFiles {
file := filepath.Join("testdata", name+".txt")
enc := hexFile(file)
if counter == 0 {
//make whoareyou header
testPacket = enc[:sizeofStaticPacketData-1]
testPacket = append(testPacket, 255)
}
if counter == 1 {
//append invalid auth size
testPacket = append(testPacket, enc[sizeofStaticPacketData:]...)
}
}
wantErr := "invalid auth size"
if _, err := net.nodeB.decode(testPacket); strings.HasSuffix(err.Error(), wantErr) {
t.Fatal(fmt.Errorf("(%s) got err %q, want %q", net.nodeB.ln.ID().TerminalString(), err, wantErr))
}
})
} }
// This test checks that all test vectors can be decoded. // This test checks that all test vectors can be decoded.

View file

@ -566,17 +566,17 @@ func (c *ChainConfig) IsShanghai(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.ShanghaiTime, time) return c.IsLondon(num) && isTimestampForked(c.ShanghaiTime, time)
} }
// IsCancun returns whether num is either equal to the Cancun fork time or greater. // IsCancun returns whether time is either equal to the Cancun fork time or greater.
func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool { func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.CancunTime, time) return c.IsLondon(num) && isTimestampForked(c.CancunTime, time)
} }
// IsPrague returns whether num is either equal to the Prague fork time or greater. // IsPrague returns whether time is either equal to the Prague fork time or greater.
func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool { func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.PragueTime, time) return c.IsLondon(num) && isTimestampForked(c.PragueTime, time)
} }
// IsVerkle returns whether num is either equal to the Verkle fork time or greater. // IsVerkle returns whether time is either equal to the Verkle fork time or greater.
func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool { func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time) return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time)
} }

View file

@ -23,7 +23,7 @@ import (
const ( const (
VersionMajor = 1 // Major version component of the current release VersionMajor = 1 // Major version component of the current release
VersionMinor = 14 // Minor version component of the current release VersionMinor = 14 // Minor version component of the current release
VersionPatch = 1 // Patch version component of the current release VersionPatch = 2 // Patch version component of the current release
VersionMeta = "unstable" // Version metadata to append to the version string VersionMeta = "unstable" // Version metadata to append to the version string
) )

View file

@ -90,7 +90,7 @@ func (b *nodebuffer) commit(nodes map[common.Hash]map[string]*trienode.Node) *no
// The nodes belong to original diff layer are still accessible even // The nodes belong to original diff layer are still accessible even
// after merging, thus the ownership of nodes map should still belong // after merging, thus the ownership of nodes map should still belong
// to original layer and any mutation on it should be prevented. // to original layer and any mutation on it should be prevented.
current = make(map[string]*trienode.Node) current = make(map[string]*trienode.Node, len(subset))
for path, n := range subset { for path, n := range subset {
current[path] = n current[path] = n
delta += int64(len(n.Blob) + len(path)) delta += int64(len(n.Blob) + len(path))