mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-28 07:36:44 +00:00
Merge branch 'ethereum:master' into portal
This commit is contained in:
commit
c5236fc9a9
101 changed files with 673 additions and 591 deletions
|
|
@ -21,10 +21,14 @@ linters:
|
|||
- staticcheck
|
||||
- bidichk
|
||||
- durationcheck
|
||||
- exportloopref
|
||||
- copyloopvar
|
||||
- whitespace
|
||||
- revive # only certain checks enabled
|
||||
|
||||
- durationcheck
|
||||
- gocheckcompilerdirectives
|
||||
- reassign
|
||||
- mirror
|
||||
- tenv
|
||||
### linters we tried and will not be using:
|
||||
###
|
||||
# - structcheck # lots of false positives
|
||||
|
|
|
|||
|
|
@ -1199,7 +1199,6 @@ func TestUnpackRevert(t *testing.T) {
|
|||
{"4e487b7100000000000000000000000000000000000000000000000000000000000000ff", "unknown panic code: 0xff", nil},
|
||||
}
|
||||
for index, c := range cases {
|
||||
index, c := index, c
|
||||
t.Run(fmt.Sprintf("case %d", index), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got, err := UnpackRevert(common.Hex2Bytes(c.input))
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
|
|||
}
|
||||
// Parse library references.
|
||||
for pattern, name := range libs {
|
||||
matched, err := regexp.Match("__\\$"+pattern+"\\$__", []byte(contracts[types[i]].InputBin))
|
||||
matched, err := regexp.MatchString("__\\$"+pattern+"\\$__", contracts[types[i]].InputBin)
|
||||
if err != nil {
|
||||
log.Error("Could not search for pattern", "pattern", pattern, "contract", contracts[types[i]], "err", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -331,7 +331,6 @@ func TestEventTupleUnpack(t *testing.T) {
|
|||
|
||||
for _, tc := range testCases {
|
||||
assert := assert.New(t)
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := unpackTestEventData(tc.dest, tc.data, tc.jsonLog, assert)
|
||||
if tc.error == "" {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ import (
|
|||
func TestPack(t *testing.T) {
|
||||
t.Parallel()
|
||||
for i, test := range packUnpackTests {
|
||||
i, test := i, test
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
encb, err := hex.DecodeString(test.packed)
|
||||
|
|
|
|||
|
|
@ -172,7 +172,6 @@ var reflectTests = []reflectTest{
|
|||
func TestReflectNameToStruct(t *testing.T) {
|
||||
t.Parallel()
|
||||
for _, test := range reflectTests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m, err := mapArgNamesToStructFields(test.args, reflect.ValueOf(test.struc))
|
||||
|
|
|
|||
|
|
@ -137,7 +137,6 @@ func TestMakeTopics(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got, err := MakeTopics(tt.args.query...)
|
||||
|
|
@ -373,7 +372,6 @@ func TestParseTopics(t *testing.T) {
|
|||
tests := setupTopicsTests()
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
createObj := tt.args.createObj()
|
||||
|
|
@ -393,7 +391,6 @@ func TestParseTopicsIntoMap(t *testing.T) {
|
|||
tests := setupTopicsTests()
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
outMap := make(map[string]interface{})
|
||||
|
|
|
|||
|
|
@ -389,7 +389,6 @@ func TestMethodMultiReturn(t *testing.T) {
|
|||
"Can not unpack into a slice with wrong types",
|
||||
}}
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require := require.New(t)
|
||||
err := abi.UnpackIntoInterface(tc.dest, "multi", data)
|
||||
|
|
@ -947,7 +946,7 @@ func TestOOMMaliciousInput(t *testing.T) {
|
|||
}
|
||||
encb, err := hex.DecodeString(test.enc)
|
||||
if err != nil {
|
||||
t.Fatalf("invalid hex: %s" + test.enc)
|
||||
t.Fatalf("invalid hex: %s", test.enc)
|
||||
}
|
||||
_, err = abi.Methods["method"].Outputs.UnpackValues(encb)
|
||||
if err == nil {
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ func (ec *engineClient) updateLoop(headCh <-chan types.ChainHeadEvent) {
|
|||
}
|
||||
|
||||
func (ec *engineClient) callNewPayload(fork string, event types.ChainHeadEvent) (string, error) {
|
||||
execData := engine.BlockToExecutableData(event.Block, nil, nil).ExecutionPayload
|
||||
execData := engine.BlockToExecutableData(event.Block, nil, nil, nil).ExecutionPayload
|
||||
|
||||
var (
|
||||
method string
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) {
|
|||
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
||||
Requests []hexutil.Bytes `json:"executionRequests"`
|
||||
Override bool `json:"shouldOverrideBuilder"`
|
||||
Witness *hexutil.Bytes `json:"witness"`
|
||||
Witness *hexutil.Bytes `json:"witness,omitempty"`
|
||||
}
|
||||
var enc ExecutionPayloadEnvelope
|
||||
enc.ExecutionPayload = e.ExecutionPayload
|
||||
|
|
@ -45,7 +45,7 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
|
|||
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
||||
Requests []hexutil.Bytes `json:"executionRequests"`
|
||||
Override *bool `json:"shouldOverrideBuilder"`
|
||||
Witness *hexutil.Bytes `json:"witness"`
|
||||
Witness *hexutil.Bytes `json:"witness,omitempty"`
|
||||
}
|
||||
var dec ExecutionPayloadEnvelope
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ type ExecutionPayloadEnvelope struct {
|
|||
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
||||
Requests [][]byte `json:"executionRequests"`
|
||||
Override bool `json:"shouldOverrideBuilder"`
|
||||
Witness *hexutil.Bytes `json:"witness"`
|
||||
Witness *hexutil.Bytes `json:"witness,omitempty"`
|
||||
}
|
||||
|
||||
type BlobsBundleV1 struct {
|
||||
|
|
@ -260,7 +260,15 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
|
|||
|
||||
var requestsHash *common.Hash
|
||||
if requests != nil {
|
||||
h := types.CalcRequestsHash(requests)
|
||||
// Put back request type byte.
|
||||
typedRequests := make([][]byte, len(requests))
|
||||
for i, reqdata := range requests {
|
||||
typedReqdata := make([]byte, len(reqdata)+1)
|
||||
typedReqdata[0] = byte(i)
|
||||
copy(typedReqdata[1:], reqdata)
|
||||
typedRequests[i] = typedReqdata
|
||||
}
|
||||
h := types.CalcRequestsHash(typedRequests)
|
||||
requestsHash = &h
|
||||
}
|
||||
|
||||
|
|
@ -294,7 +302,7 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
|
|||
|
||||
// BlockToExecutableData constructs the ExecutableData structure by filling the
|
||||
// fields from the given block. It assumes the given block is post-merge block.
|
||||
func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.BlobTxSidecar) *ExecutionPayloadEnvelope {
|
||||
func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.BlobTxSidecar, requests [][]byte) *ExecutionPayloadEnvelope {
|
||||
data := &ExecutableData{
|
||||
BlockHash: block.Hash(),
|
||||
ParentHash: block.ParentHash(),
|
||||
|
|
@ -315,6 +323,8 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
|
|||
ExcessBlobGas: block.ExcessBlobGas(),
|
||||
ExecutionWitness: block.ExecutionWitness(),
|
||||
}
|
||||
|
||||
// Add blobs.
|
||||
bundle := BlobsBundleV1{
|
||||
Commitments: make([]hexutil.Bytes, 0),
|
||||
Blobs: make([]hexutil.Bytes, 0),
|
||||
|
|
@ -327,7 +337,23 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
|
|||
bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:]))
|
||||
}
|
||||
}
|
||||
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false}
|
||||
|
||||
// Remove type byte in requests.
|
||||
var plainRequests [][]byte
|
||||
if requests != nil {
|
||||
plainRequests = make([][]byte, len(requests))
|
||||
for i, reqdata := range requests {
|
||||
plainRequests[i] = reqdata[1:]
|
||||
}
|
||||
}
|
||||
|
||||
return &ExecutionPayloadEnvelope{
|
||||
ExecutionPayload: data,
|
||||
BlockValue: fees,
|
||||
BlobsBundle: &bundle,
|
||||
Requests: plainRequests,
|
||||
Override: false,
|
||||
}
|
||||
}
|
||||
|
||||
// ExecutionPayloadBody is used in the response to GetPayloadBodiesByHash and GetPayloadBodiesByRange
|
||||
|
|
|
|||
|
|
@ -56,37 +56,37 @@ f45af3e1434175ff85620a74c07fb41d6844655f1f2cd2389c5fca6de000f58c go1.23.2.freeb
|
|||
f626cdd92fc21a88b31c1251f419c17782933a42903db87a174ce74eeecc66a9 go1.23.2.linux-arm64.tar.gz
|
||||
fa70d39ddeb6b55241a30b48d7af4e681c6a7d7104e8326c3bc1b12a75e091cc go1.23.2.solaris-amd64.tar.gz
|
||||
|
||||
# version:golangci 1.59.0
|
||||
# version:golangci 1.61.0
|
||||
# https://github.com/golangci/golangci-lint/releases/
|
||||
# https://github.com/golangci/golangci-lint/releases/download/v1.59.0/
|
||||
418acf7e255ddc0783e97129c9b03d9311b77826a5311d425a01c708a86417e7 golangci-lint-1.59.0-darwin-amd64.tar.gz
|
||||
5f6a1d95a6dd69f6e328eb56dd311a38e04cfab79a1305fbf4957f4e203f47b6 golangci-lint-1.59.0-darwin-arm64.tar.gz
|
||||
8899bf589185d49f747f3e5db9f0bde8a47245a100c64a3dd4d65e8e92cfc4f2 golangci-lint-1.59.0-freebsd-386.tar.gz
|
||||
658212f138d9df2ac89427e22115af34bf387c0871d70f2a25101718946a014f golangci-lint-1.59.0-freebsd-amd64.tar.gz
|
||||
4c6395ea40f314d3b6fa17d8997baab93464d5d1deeaab513155e625473bd03a golangci-lint-1.59.0-freebsd-armv6.tar.gz
|
||||
ff37da4fbaacdb6bbae70fdbdbb1ba932a859956f788c82822fa06bef5b7c6b3 golangci-lint-1.59.0-freebsd-armv7.tar.gz
|
||||
439739469ed2bda182b1ec276d40c40e02f195537f78e3672996741ad223d6b6 golangci-lint-1.59.0-illumos-amd64.tar.gz
|
||||
940801d46790e40d0a097d8fee34e2606f0ef148cd039654029b0b8750a15ed6 golangci-lint-1.59.0-linux-386.tar.gz
|
||||
3b14a439f33c4fff83dbe0349950d984042b9a1feb6c62f82787b598fc3ab5f4 golangci-lint-1.59.0-linux-amd64.tar.gz
|
||||
c57e6c0b0fa03089a2611dceddd5bc5d206716cccdff8b149da8baac598719a1 golangci-lint-1.59.0-linux-arm64.tar.gz
|
||||
93149e2d3b25ac754df9a23172403d8aa6d021a7e0d9c090a12f51897f68c9a0 golangci-lint-1.59.0-linux-armv6.tar.gz
|
||||
d10ac38239d9efee3ee87b55c96cdf3fa09e1a525babe3ffdaaf65ccc48cf3dc golangci-lint-1.59.0-linux-armv7.tar.gz
|
||||
047338114b4f0d5f08f0fb9a397b03cc171916ed0960be7dfb355c2320cd5e9c golangci-lint-1.59.0-linux-loong64.tar.gz
|
||||
5632df0f7f8fc03a80a266130faef0b5902d280cf60621f1b2bdc1aef6d97ee9 golangci-lint-1.59.0-linux-mips64.tar.gz
|
||||
71dd638c82fa4439171e7126d2c7a32b5d103bfdef282cea40c83632cb3d1f4b golangci-lint-1.59.0-linux-mips64le.tar.gz
|
||||
6cf9ea0d34e91669948483f9ae7f07da319a879344373a1981099fbd890cde00 golangci-lint-1.59.0-linux-ppc64le.tar.gz
|
||||
af0205fa6fbab197cee613c359947711231739095d21b5c837086233b36ad971 golangci-lint-1.59.0-linux-riscv64.tar.gz
|
||||
a9d2fb93f3c688ebccef94f5dc96c0b07c4d20bf6556cddebd8442159b0c80f6 golangci-lint-1.59.0-linux-s390x.tar.gz
|
||||
68ab4c57a847b8ace9679887f2f8b2b6760e57ee29dcde8c3f40dd8bb2654fa2 golangci-lint-1.59.0-netbsd-386.tar.gz
|
||||
d277b8b435c19406d00de4d509eadf5a024a5782878332e9a1b7c02bb76e87a7 golangci-lint-1.59.0-netbsd-amd64.tar.gz
|
||||
83211656be8dcfa1545af4f92894409f412d1f37566798cb9460a526593ad62c golangci-lint-1.59.0-netbsd-arm64.tar.gz
|
||||
6c6866d28bf79fa9817a0f7d2b050890ed109cae80bdb4dfa39536a7226da237 golangci-lint-1.59.0-netbsd-armv6.tar.gz
|
||||
11587566363bd03ca586b7df9776ccaed569fcd1f3489930ac02f9375b307503 golangci-lint-1.59.0-netbsd-armv7.tar.gz
|
||||
466181a8967bafa495e41494f93a0bec829c2cf715de874583b0460b3b8ae2b8 golangci-lint-1.59.0-windows-386.zip
|
||||
3317d8a87a99a49a0a1321d295c010790e6dbf43ee96b318f4b8bb23eae7a565 golangci-lint-1.59.0-windows-amd64.zip
|
||||
b3af955c7fceac8220a36fc799e1b3f19d3b247d32f422caac5f9845df8f7316 golangci-lint-1.59.0-windows-arm64.zip
|
||||
6f083c7d0c764e5a0e5bde46ee3e91ae357d80c194190fe1d9754392e9064c7e golangci-lint-1.59.0-windows-armv6.zip
|
||||
3709b4dd425deadab27748778d08e03c0f804d7748f7dd5b6bb488d98aa031c7 golangci-lint-1.59.0-windows-armv7.zip
|
||||
# https://github.com/golangci/golangci-lint/releases/download/v1.61.0/
|
||||
5c280ef3284f80c54fd90d73dc39ca276953949da1db03eb9dd0fbf868cc6e55 golangci-lint-1.61.0-darwin-amd64.tar.gz
|
||||
544334890701e4e04a6e574bc010bea8945205c08c44cced73745a6378012d36 golangci-lint-1.61.0-darwin-arm64.tar.gz
|
||||
e885a6f561092055930ebd298914d80e8fd2e10d2b1e9942836c2c6a115301fa golangci-lint-1.61.0-freebsd-386.tar.gz
|
||||
b13f6a3f11f65e7ff66b734d7554df3bbae0f485768848424e7554ed289e19c2 golangci-lint-1.61.0-freebsd-amd64.tar.gz
|
||||
cd8e7bbe5b8f33ed1597aa1cc588da96a3b9f22e1b9ae60d93511eae1a0ee8c5 golangci-lint-1.61.0-freebsd-armv6.tar.gz
|
||||
7ade524dbd88bd250968f45e190af90e151fa5ee63dd6aa7f7bb90e8155db61d golangci-lint-1.61.0-freebsd-armv7.tar.gz
|
||||
0fe3cd8a1ed8d9f54f48670a5af3df056d6040d94017057f0f4d65c930660ad9 golangci-lint-1.61.0-illumos-amd64.tar.gz
|
||||
b463fc5053a612abd26393ebaff1d85d7d56058946f4f0f7bf25ed44ea899415 golangci-lint-1.61.0-linux-386.tar.gz
|
||||
77cb0af99379d9a21d5dc8c38364d060e864a01bd2f3e30b5e8cc550c3a54111 golangci-lint-1.61.0-linux-amd64.tar.gz
|
||||
af60ac05566d9351615cb31b4cc070185c25bf8cbd9b09c1873aa5ec6f3cc17e golangci-lint-1.61.0-linux-arm64.tar.gz
|
||||
1f307f2fcc5d7d674062a967a0d83a7091e300529aa237ec6ad2b3dd14c897f5 golangci-lint-1.61.0-linux-armv6.tar.gz
|
||||
3ad8cbaae75a547450844811300f99c4cd290277398e43d22b9eb1792d15af4c golangci-lint-1.61.0-linux-armv7.tar.gz
|
||||
9be2ca67d961d7699079739cf6f7c8291c5183d57e34d1677de21ca19d0bd3ed golangci-lint-1.61.0-linux-loong64.tar.gz
|
||||
90d005e1648115ebf0861b408eab9c936079a24763e883058b0a227cd3135d31 golangci-lint-1.61.0-linux-mips64.tar.gz
|
||||
6d2ed4f49407115460b8c10ccfc40fd177e0887a48864a2879dd16e84ba2a48c golangci-lint-1.61.0-linux-mips64le.tar.gz
|
||||
633089589af5a58b7430afb6eee107d4e9c99e8d91711ddc219eb13a07e8d3b8 golangci-lint-1.61.0-linux-ppc64le.tar.gz
|
||||
4c1a097d9e0d1b4a8144dae6a1f5583a38d662f3bdc1498c4e954b6ed856be98 golangci-lint-1.61.0-linux-riscv64.tar.gz
|
||||
30581d3c987d287b7064617f1a2694143e10dffc40bc25be6636006ee82d7e1c golangci-lint-1.61.0-linux-s390x.tar.gz
|
||||
42530bf8100bd43c07f5efe6d92148ba6c5a7a712d510c6f24be85af6571d5eb golangci-lint-1.61.0-netbsd-386.tar.gz
|
||||
b8bb07c920f6601edf718d5e82ec0784fd590b0992b42b6ec18da99f26013ed4 golangci-lint-1.61.0-netbsd-amd64.tar.gz
|
||||
353a51527c60bd0776b0891b03f247c791986f625fca689d121972c624e54198 golangci-lint-1.61.0-netbsd-arm64.tar.gz
|
||||
957a6272c3137910514225704c5dac0723b9c65eb7d9587366a997736e2d7580 golangci-lint-1.61.0-netbsd-armv6.tar.gz
|
||||
a89eb28ff7f18f5cd52b914739360fa95cf2f643de4adeca46e26bec3a07e8d8 golangci-lint-1.61.0-netbsd-armv7.tar.gz
|
||||
d8d74c43600b271393000717a4ed157d7a15bb85bab7db2efad9b63a694d4634 golangci-lint-1.61.0-windows-386.zip
|
||||
e7bc2a81929a50f830244d6d2e657cce4f19a59aff49fa9000176ff34fda64ce golangci-lint-1.61.0-windows-amd64.zip
|
||||
ed97c221596dd771e3dd9344872c140340bee2e819cd7a90afa1de752f1f2e0f golangci-lint-1.61.0-windows-arm64.zip
|
||||
4b365233948b13d02d45928a5c390045e00945e919747b9887b5f260247541ae golangci-lint-1.61.0-windows-armv6.zip
|
||||
595538fb64d152173959d28f6235227f9cd969a828e5af0c4e960d02af4ffd0e golangci-lint-1.61.0-windows-armv7.zip
|
||||
|
||||
# This is the builder on PPA that will build Go itself (inception-y), don't modify!
|
||||
#
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@ func (c *Chain) AccountsInHashOrder() []state.DumpAccount {
|
|||
list := make([]state.DumpAccount, len(c.state))
|
||||
i := 0
|
||||
for addr, acc := range c.state {
|
||||
addr := addr
|
||||
list[i] = acc
|
||||
list[i].Address = &addr
|
||||
if len(acc.AddressHash) != 32 {
|
||||
|
|
|
|||
|
|
@ -286,7 +286,6 @@ a key before startingHash (wrong order). The server should return the first avai
|
|||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
tc := tc
|
||||
if i > 0 {
|
||||
t.Log("\n")
|
||||
}
|
||||
|
|
@ -429,7 +428,6 @@ of the test account. The server should return slots [2,3] (i.e. the 'next availa
|
|||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
tc := tc
|
||||
if i > 0 {
|
||||
t.Log("\n")
|
||||
}
|
||||
|
|
@ -526,7 +524,6 @@ func (s *Suite) TestSnapGetByteCodes(t *utesting.T) {
|
|||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
tc := tc
|
||||
if i > 0 {
|
||||
t.Log("\n")
|
||||
}
|
||||
|
|
@ -723,7 +720,6 @@ The server should reject the request.`,
|
|||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
tc := tc
|
||||
if i > 0 {
|
||||
t.Log("\n")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ type rejectedTx struct {
|
|||
// Apply applies a set of transactions to a pre-state
|
||||
func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
txIt txIterator, miningReward int64,
|
||||
getTracerFn func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) {
|
||||
getTracerFn func(txIndex int, txHash common.Hash, chainConfig *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) {
|
||||
// Capture errors for BLOCKHASH operation, if we haven't been supplied the
|
||||
// required blockhashes
|
||||
var hashError error
|
||||
|
|
@ -242,7 +242,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
continue
|
||||
}
|
||||
}
|
||||
tracer, traceOutput, err := getTracerFn(txIndex, tx.Hash())
|
||||
tracer, traceOutput, err := getTracerFn(txIndex, tx.Hash(), chainConfig)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,9 @@ type input struct {
|
|||
}
|
||||
|
||||
func Transition(ctx *cli.Context) error {
|
||||
var getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { return nil, nil, nil }
|
||||
var getTracer = func(txIndex int, txHash common.Hash, chainConfig *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
baseDir, err := createBasedir(ctx)
|
||||
if err != nil {
|
||||
|
|
@ -97,7 +99,7 @@ func Transition(ctx *cli.Context) error {
|
|||
EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name),
|
||||
Debug: true,
|
||||
}
|
||||
getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) {
|
||||
getTracer = func(txIndex int, txHash common.Hash, _ *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error) {
|
||||
traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String())))
|
||||
if err != nil {
|
||||
return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err))
|
||||
|
|
@ -121,12 +123,12 @@ func Transition(ctx *cli.Context) error {
|
|||
if ctx.IsSet(TraceTracerConfigFlag.Name) {
|
||||
config = []byte(ctx.String(TraceTracerConfigFlag.Name))
|
||||
}
|
||||
getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) {
|
||||
getTracer = func(txIndex int, txHash common.Hash, chainConfig *params.ChainConfig) (*tracers.Tracer, io.WriteCloser, error) {
|
||||
traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.json", txIndex, txHash.String())))
|
||||
if err != nil {
|
||||
return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err))
|
||||
}
|
||||
tracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config)
|
||||
tracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config, chainConfig)
|
||||
if err != nil {
|
||||
return nil, nil, NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %w", err))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -524,7 +524,7 @@ func TestT9n(t *testing.T) {
|
|||
ok, err := cmpJson(have, want)
|
||||
switch {
|
||||
case err != nil:
|
||||
t.Logf(string(have))
|
||||
t.Log(string(have))
|
||||
t.Fatalf("test %d, json parsing failed: %v", i, err)
|
||||
case !ok:
|
||||
t.Fatalf("test %d: output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want))
|
||||
|
|
@ -659,7 +659,7 @@ func TestB11r(t *testing.T) {
|
|||
ok, err := cmpJson(have, want)
|
||||
switch {
|
||||
case err != nil:
|
||||
t.Logf(string(have))
|
||||
t.Log(string(have))
|
||||
t.Fatalf("test %d, json parsing failed: %v", i, err)
|
||||
case !ok:
|
||||
t.Fatalf("test %d: output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want))
|
||||
|
|
|
|||
|
|
@ -113,7 +113,6 @@ func TestAccountImport(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
importAccountWithExpect(t, test.key, test.output)
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ func remoteConsole(ctx *cli.Context) error {
|
|||
func ephemeralConsole(ctx *cli.Context) error {
|
||||
var b strings.Builder
|
||||
for _, file := range ctx.Args().Slice() {
|
||||
b.Write([]byte(fmt.Sprintf("loadScript('%s');", file)))
|
||||
b.WriteString(fmt.Sprintf("loadScript('%s');", file))
|
||||
}
|
||||
utils.Fatalf(`The "js" command is deprecated. Please use the following instead:
|
||||
geth --exec "%s" console`, b.String())
|
||||
|
|
|
|||
|
|
@ -170,7 +170,6 @@ func TestKeyID(t *testing.T) {
|
|||
{"third key", args{id: extractKeyId(gethPubKeys[2])}, "FD9813B2D2098484"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := keyID(tt.args.id); got != tt.want {
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ func dump(in *inStream, s *rlp.Stream, depth int, out io.Writer) error {
|
|||
s.List()
|
||||
defer s.ListEnd()
|
||||
if size == 0 {
|
||||
fmt.Fprintf(out, ws(depth)+"[]")
|
||||
fmt.Fprint(out, ws(depth)+"[]")
|
||||
} else {
|
||||
fmt.Fprintln(out, ws(depth)+"[")
|
||||
for i := 0; ; i++ {
|
||||
|
|
|
|||
|
|
@ -544,6 +544,7 @@ var (
|
|||
VMTraceJsonConfigFlag = &cli.StringFlag{
|
||||
Name: "vmtrace.jsonconfig",
|
||||
Usage: "Tracer configuration (JSON)",
|
||||
Value: "{}",
|
||||
Category: flags.VMCategory,
|
||||
}
|
||||
// API options.
|
||||
|
|
@ -1980,13 +1981,8 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
|||
// VM tracing config.
|
||||
if ctx.IsSet(VMTraceFlag.Name) {
|
||||
if name := ctx.String(VMTraceFlag.Name); name != "" {
|
||||
var config string
|
||||
if ctx.IsSet(VMTraceJsonConfigFlag.Name) {
|
||||
config = ctx.String(VMTraceJsonConfigFlag.Name)
|
||||
}
|
||||
|
||||
cfg.VMTrace = name
|
||||
cfg.VMTraceJsonConfig = config
|
||||
cfg.VMTraceJsonConfig = ctx.String(VMTraceJsonConfigFlag.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2267,10 +2263,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
|||
}
|
||||
if ctx.IsSet(VMTraceFlag.Name) {
|
||||
if name := ctx.String(VMTraceFlag.Name); name != "" {
|
||||
var config json.RawMessage
|
||||
if ctx.IsSet(VMTraceJsonConfigFlag.Name) {
|
||||
config = json.RawMessage(ctx.String(VMTraceJsonConfigFlag.Name))
|
||||
}
|
||||
config := json.RawMessage(ctx.String(VMTraceJsonConfigFlag.Name))
|
||||
t, err := tracers.LiveDirectory.New(name, config)
|
||||
if err != nil {
|
||||
Fatalf("Failed to create tracer %q: %v", name, err)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ func Test_SplitTagsFlag(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := SplitTagsFlag(tt.args); !reflect.DeepEqual(got, tt.want) {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ func TestGetPassPhraseWithList(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := GetPassPhraseWithList(tt.args.text, tt.args.confirmation, tt.args.index, tt.args.passwords); got != tt.want {
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
|||
// such as amount of used gas, the receipt roots and the state root itself.
|
||||
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, res *ProcessResult, stateless bool) error {
|
||||
if res == nil {
|
||||
return fmt.Errorf("nil ProcessResult value")
|
||||
return errors.New("nil ProcessResult value")
|
||||
}
|
||||
header := block.Header()
|
||||
if block.GasUsed() != res.GasUsed {
|
||||
|
|
@ -150,7 +150,7 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||
return fmt.Errorf("invalid requests hash (remote: %x local: %x)", *header.RequestsHash, reqhash)
|
||||
}
|
||||
} else if res.Requests != nil {
|
||||
return fmt.Errorf("block has requests before prague fork")
|
||||
return errors.New("block has requests before prague fork")
|
||||
}
|
||||
// Validate the state root against the received state root and throw
|
||||
// an error if they don't match.
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"io"
|
||||
"math/big"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
|
@ -224,7 +225,6 @@ type BlockChain struct {
|
|||
hc *HeaderChain
|
||||
rmLogsFeed event.Feed
|
||||
chainFeed event.Feed
|
||||
chainSideFeed event.Feed
|
||||
chainHeadFeed event.Feed
|
||||
logsFeed event.Feed
|
||||
blockProcFeed event.Feed
|
||||
|
|
@ -571,15 +571,14 @@ func (bc *BlockChain) SetHead(head uint64) error {
|
|||
}
|
||||
// Send chain head event to update the transaction pool
|
||||
header := bc.CurrentBlock()
|
||||
block := bc.GetBlock(header.Hash(), header.Number.Uint64())
|
||||
if block == nil {
|
||||
if block := bc.GetBlock(header.Hash(), header.Number.Uint64()); block == nil {
|
||||
// This should never happen. In practice, previously 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})
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Header: header})
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -593,15 +592,14 @@ func (bc *BlockChain) SetHeadWithTimestamp(timestamp uint64) error {
|
|||
}
|
||||
// Send chain head event to update the transaction pool
|
||||
header := bc.CurrentBlock()
|
||||
block := bc.GetBlock(header.Hash(), header.Number.Uint64())
|
||||
if block == nil {
|
||||
if block := bc.GetBlock(header.Hash(), header.Number.Uint64()); block == nil {
|
||||
// This should never happen. In practice, previously 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})
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Header: header})
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -1438,7 +1436,7 @@ func (bc *BlockChain) writeBlockWithoutState(block *types.Block, td *big.Int) (e
|
|||
func (bc *BlockChain) writeKnownBlock(block *types.Block) error {
|
||||
current := bc.CurrentBlock()
|
||||
if block.ParentHash() != current.Hash() {
|
||||
if err := bc.reorg(current, block); err != nil {
|
||||
if err := bc.reorg(current, block.Header()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -1544,7 +1542,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
|
|||
|
||||
// Reorganise the chain if the parent is not the head block
|
||||
if block.ParentHash() != currentBlock.Hash() {
|
||||
if err := bc.reorg(currentBlock, block); err != nil {
|
||||
if err := bc.reorg(currentBlock, block.Header()); err != nil {
|
||||
return NonStatTy, err
|
||||
}
|
||||
}
|
||||
|
|
@ -1552,7 +1550,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
|
|||
// Set new head.
|
||||
bc.writeHeadBlock(block)
|
||||
|
||||
bc.chainFeed.Send(ChainEvent{Block: block, Hash: block.Hash(), Logs: logs})
|
||||
bc.chainFeed.Send(ChainEvent{Header: block.Header()})
|
||||
if len(logs) > 0 {
|
||||
bc.logsFeed.Send(logs)
|
||||
}
|
||||
|
|
@ -1562,7 +1560,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
|
|||
// we will fire an accumulated ChainHeadEvent and disable fire
|
||||
// event here.
|
||||
if emitHeadEvent {
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Block: block})
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Header: block.Header()})
|
||||
}
|
||||
return CanonStatTy, nil
|
||||
}
|
||||
|
|
@ -1627,7 +1625,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
|
|||
// Fire a single chain head event if we've progressed the chain
|
||||
defer func() {
|
||||
if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() {
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{lastCanon})
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Header: lastCanon.Header()})
|
||||
}
|
||||
}()
|
||||
// Start the parallel header verifier
|
||||
|
|
@ -2157,8 +2155,8 @@ func (bc *BlockChain) recoverAncestors(block *types.Block, makeWitness bool) (co
|
|||
return block.Hash(), nil
|
||||
}
|
||||
|
||||
// collectLogs collects the logs that were generated or removed during
|
||||
// the processing of a block. These logs are later announced as deleted or reborn.
|
||||
// collectLogs collects the logs that were generated or removed during 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 {
|
||||
var blobGasPrice *big.Int
|
||||
excessBlobGas := b.ExcessBlobGas()
|
||||
|
|
@ -2184,70 +2182,55 @@ func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log {
|
|||
// reorg takes two blocks, an old chain and a new chain and will reconstruct the
|
||||
// blocks and inserts them to be part of the new canonical chain and accumulates
|
||||
// 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(oldHead *types.Header, newHead *types.Block) error {
|
||||
func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Header) error {
|
||||
var (
|
||||
newChain types.Blocks
|
||||
oldChain types.Blocks
|
||||
commonBlock *types.Block
|
||||
|
||||
deletedTxs []common.Hash
|
||||
addedTxs []common.Hash
|
||||
newChain []*types.Header
|
||||
oldChain []*types.Header
|
||||
commonBlock *types.Header
|
||||
)
|
||||
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() {
|
||||
if oldHead.Number.Uint64() > newHead.Number.Uint64() {
|
||||
// Old chain is longer, gather all transactions and logs as deleted ones
|
||||
for ; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = bc.GetBlock(oldBlock.ParentHash(), oldBlock.NumberU64()-1) {
|
||||
oldChain = append(oldChain, oldBlock)
|
||||
for _, tx := range oldBlock.Transactions() {
|
||||
deletedTxs = append(deletedTxs, tx.Hash())
|
||||
}
|
||||
for ; oldHead != nil && oldHead.Number.Uint64() != newHead.Number.Uint64(); oldHead = bc.GetHeader(oldHead.ParentHash, oldHead.Number.Uint64()-1) {
|
||||
oldChain = append(oldChain, oldHead)
|
||||
}
|
||||
} else {
|
||||
// New chain is longer, stash all blocks away for subsequent insertion
|
||||
for ; newBlock != nil && newBlock.NumberU64() != oldBlock.NumberU64(); newBlock = bc.GetBlock(newBlock.ParentHash(), newBlock.NumberU64()-1) {
|
||||
newChain = append(newChain, newBlock)
|
||||
for ; newHead != nil && newHead.Number.Uint64() != oldHead.Number.Uint64(); newHead = bc.GetHeader(newHead.ParentHash, newHead.Number.Uint64()-1) {
|
||||
newChain = append(newChain, newHead)
|
||||
}
|
||||
}
|
||||
if oldBlock == nil {
|
||||
if oldHead == nil {
|
||||
return errInvalidOldChain
|
||||
}
|
||||
if newBlock == nil {
|
||||
if newHead == nil {
|
||||
return errInvalidNewChain
|
||||
}
|
||||
// Both sides of the reorg are at the same number, reduce both until the common
|
||||
// ancestor is found
|
||||
for {
|
||||
// If the common ancestor was found, bail out
|
||||
if oldBlock.Hash() == newBlock.Hash() {
|
||||
commonBlock = oldBlock
|
||||
if oldHead.Hash() == newHead.Hash() {
|
||||
commonBlock = oldHead
|
||||
break
|
||||
}
|
||||
// Remove an old block as well as stash away a new block
|
||||
oldChain = append(oldChain, oldBlock)
|
||||
for _, tx := range oldBlock.Transactions() {
|
||||
deletedTxs = append(deletedTxs, tx.Hash())
|
||||
}
|
||||
newChain = append(newChain, newBlock)
|
||||
oldChain = append(oldChain, oldHead)
|
||||
newChain = append(newChain, newHead)
|
||||
|
||||
// Step back with both chains
|
||||
oldBlock = bc.GetBlock(oldBlock.ParentHash(), oldBlock.NumberU64()-1)
|
||||
if oldBlock == nil {
|
||||
oldHead = bc.GetHeader(oldHead.ParentHash, oldHead.Number.Uint64()-1)
|
||||
if oldHead == nil {
|
||||
return errInvalidOldChain
|
||||
}
|
||||
newBlock = bc.GetBlock(newBlock.ParentHash(), newBlock.NumberU64()-1)
|
||||
if newBlock == nil {
|
||||
newHead = bc.GetHeader(newHead.ParentHash, newHead.Number.Uint64()-1)
|
||||
if newHead == nil {
|
||||
return errInvalidNewChain
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the user sees large reorgs
|
||||
if len(oldChain) > 0 && len(newChain) > 0 {
|
||||
logFn := log.Info
|
||||
|
|
@ -2256,7 +2239,7 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
|
|||
msg = "Large chain reorg detected"
|
||||
logFn = log.Warn
|
||||
}
|
||||
logFn(msg, "number", commonBlock.Number(), "hash", commonBlock.Hash(),
|
||||
logFn(msg, "number", commonBlock.Number, "hash", commonBlock.Hash(),
|
||||
"drop", len(oldChain), "dropfrom", oldChain[0].Hash(), "add", len(newChain), "addfrom", newChain[0].Hash())
|
||||
blockReorgAddMeter.Mark(int64(len(newChain)))
|
||||
blockReorgDropMeter.Mark(int64(len(oldChain)))
|
||||
|
|
@ -2264,55 +2247,112 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
|
|||
} else if len(newChain) > 0 {
|
||||
// Special case happens in the post merge stage that current head is
|
||||
// the ancestor of new head while these two blocks are not consecutive
|
||||
log.Info("Extend chain", "add", len(newChain), "number", newChain[0].Number(), "hash", newChain[0].Hash())
|
||||
log.Info("Extend chain", "add", len(newChain), "number", newChain[0].Number, "hash", newChain[0].Hash())
|
||||
blockReorgAddMeter.Mark(int64(len(newChain)))
|
||||
} else {
|
||||
// len(newChain) == 0 && len(oldChain) > 0
|
||||
// rewind the canonical chain to a lower point.
|
||||
log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "oldblocks", len(oldChain), "newnum", newBlock.Number(), "newhash", newBlock.Hash(), "newblocks", len(newChain))
|
||||
log.Error("Impossible reorg, please file an issue", "oldnum", oldHead.Number, "oldhash", oldHead.Hash(), "oldblocks", len(oldChain), "newnum", newHead.Number, "newhash", newHead.Hash(), "newblocks", len(newChain))
|
||||
}
|
||||
// Acquire the tx-lookup lock before mutation. This step is essential
|
||||
// as the txlookups should be changed atomically, and all subsequent
|
||||
// reads should be blocked until the mutation is complete.
|
||||
bc.txLookupLock.Lock()
|
||||
|
||||
// Insert the new chain segment in incremental order, from the old
|
||||
// to the new. The new chain head (newChain[0]) is not inserted here,
|
||||
// as it will be handled separately outside of this function
|
||||
for i := len(newChain) - 1; i >= 1; i-- {
|
||||
// Insert the block in the canonical way, re-writing history
|
||||
bc.writeHeadBlock(newChain[i])
|
||||
// Reorg can be executed, start reducing the chain's old blocks and appending
|
||||
// the new blocks
|
||||
var (
|
||||
deletedTxs []common.Hash
|
||||
rebirthTxs []common.Hash
|
||||
|
||||
// Collect the new added transactions.
|
||||
for _, tx := range newChain[i].Transactions() {
|
||||
addedTxs = append(addedTxs, tx.Hash())
|
||||
deletedLogs []*types.Log
|
||||
rebirthLogs []*types.Log
|
||||
)
|
||||
// Deleted log emission on the API uses forward order, which is borked, but
|
||||
// we'll leave it in for legacy reasons.
|
||||
//
|
||||
// TODO(karalabe): This should be nuked out, no idea how, deprecate some APIs?
|
||||
{
|
||||
for i := len(oldChain) - 1; i >= 0; i-- {
|
||||
block := bc.GetBlock(oldChain[i].Hash(), oldChain[i].Number.Uint64())
|
||||
if block == nil {
|
||||
return errInvalidOldChain // Corrupt database, mostly here to avoid weird panics
|
||||
}
|
||||
if logs := bc.collectLogs(block, true); len(logs) > 0 {
|
||||
deletedLogs = append(deletedLogs, logs...)
|
||||
}
|
||||
if len(deletedLogs) > 512 {
|
||||
bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs})
|
||||
deletedLogs = nil
|
||||
}
|
||||
}
|
||||
if len(deletedLogs) > 0 {
|
||||
bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs})
|
||||
}
|
||||
}
|
||||
// Undo old blocks in reverse order
|
||||
for i := 0; i < len(oldChain); i++ {
|
||||
// Collect all the deleted transactions
|
||||
block := bc.GetBlock(oldChain[i].Hash(), oldChain[i].Number.Uint64())
|
||||
if block == nil {
|
||||
return errInvalidOldChain // Corrupt database, mostly here to avoid weird panics
|
||||
}
|
||||
for _, tx := range block.Transactions() {
|
||||
deletedTxs = append(deletedTxs, tx.Hash())
|
||||
}
|
||||
// Collect deleted logs and emit them for new integrations
|
||||
if logs := bc.collectLogs(block, true); len(logs) > 0 {
|
||||
// Emit revertals latest first, older then
|
||||
slices.Reverse(logs)
|
||||
|
||||
// TODO(karalabe): Hook into the reverse emission part
|
||||
}
|
||||
}
|
||||
// Apply new blocks in forward order
|
||||
for i := len(newChain) - 1; i >= 1; i-- {
|
||||
// Collect all the included transactions
|
||||
block := bc.GetBlock(newChain[i].Hash(), newChain[i].Number.Uint64())
|
||||
if block == nil {
|
||||
return errInvalidNewChain // Corrupt database, mostly here to avoid weird panics
|
||||
}
|
||||
for _, tx := range block.Transactions() {
|
||||
rebirthTxs = append(rebirthTxs, tx.Hash())
|
||||
}
|
||||
// Collect inserted logs and emit them
|
||||
if logs := bc.collectLogs(block, false); len(logs) > 0 {
|
||||
rebirthLogs = append(rebirthLogs, logs...)
|
||||
}
|
||||
if len(rebirthLogs) > 512 {
|
||||
bc.logsFeed.Send(rebirthLogs)
|
||||
rebirthLogs = nil
|
||||
}
|
||||
// Update the head block
|
||||
bc.writeHeadBlock(block)
|
||||
}
|
||||
if len(rebirthLogs) > 0 {
|
||||
bc.logsFeed.Send(rebirthLogs)
|
||||
}
|
||||
// Delete useless indexes right now which includes the non-canonical
|
||||
// transaction indexes, canonical chain indexes which above the head.
|
||||
var (
|
||||
indexesBatch = bc.db.NewBatch()
|
||||
diffs = types.HashDifference(deletedTxs, addedTxs)
|
||||
)
|
||||
for _, tx := range diffs {
|
||||
rawdb.DeleteTxLookupEntry(indexesBatch, tx)
|
||||
batch := bc.db.NewBatch()
|
||||
for _, tx := range types.HashDifference(deletedTxs, rebirthTxs) {
|
||||
rawdb.DeleteTxLookupEntry(batch, tx)
|
||||
}
|
||||
// Delete all hash markers that are not part of the new canonical chain.
|
||||
// Because the reorg function does not handle new chain head, all hash
|
||||
// markers greater than or equal to new chain head should be deleted.
|
||||
number := commonBlock.NumberU64()
|
||||
number := commonBlock.Number
|
||||
if len(newChain) > 1 {
|
||||
number = newChain[1].NumberU64()
|
||||
number = newChain[1].Number
|
||||
}
|
||||
for i := number + 1; ; i++ {
|
||||
for i := number.Uint64() + 1; ; i++ {
|
||||
hash := rawdb.ReadCanonicalHash(bc.db, i)
|
||||
if hash == (common.Hash{}) {
|
||||
break
|
||||
}
|
||||
rawdb.DeleteCanonicalHash(indexesBatch, i)
|
||||
rawdb.DeleteCanonicalHash(batch, i)
|
||||
}
|
||||
if err := indexesBatch.Write(); err != nil {
|
||||
if err := batch.Write(); err != nil {
|
||||
log.Crit("Failed to delete useless indexes", "err", err)
|
||||
}
|
||||
// Reset the tx lookup cache to clear stale txlookup cache.
|
||||
|
|
@ -2321,43 +2361,6 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
|
|||
// Release the tx-lookup lock after mutation.
|
||||
bc.txLookupLock.Unlock()
|
||||
|
||||
// Send out events for logs from the old canon chain, and 'reborn'
|
||||
// logs from the new canon chain. The number of logs can be very
|
||||
// high, so the events are sent in batches of size around 512.
|
||||
|
||||
// Deleted logs + blocks:
|
||||
var deletedLogs []*types.Log
|
||||
for i := len(oldChain) - 1; i >= 0; i-- {
|
||||
// Also send event for blocks removed from the canon chain.
|
||||
bc.chainSideFeed.Send(ChainSideEvent{Block: oldChain[i]})
|
||||
|
||||
// Collect deleted logs for notification
|
||||
if logs := bc.collectLogs(oldChain[i], true); len(logs) > 0 {
|
||||
deletedLogs = append(deletedLogs, logs...)
|
||||
}
|
||||
if len(deletedLogs) > 512 {
|
||||
bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs})
|
||||
deletedLogs = nil
|
||||
}
|
||||
}
|
||||
if len(deletedLogs) > 0 {
|
||||
bc.rmLogsFeed.Send(RemovedLogsEvent{deletedLogs})
|
||||
}
|
||||
|
||||
// New logs:
|
||||
var rebirthLogs []*types.Log
|
||||
for i := len(newChain) - 1; i >= 1; i-- {
|
||||
if logs := bc.collectLogs(newChain[i], false); len(logs) > 0 {
|
||||
rebirthLogs = append(rebirthLogs, logs...)
|
||||
}
|
||||
if len(rebirthLogs) > 512 {
|
||||
bc.logsFeed.Send(rebirthLogs)
|
||||
rebirthLogs = nil
|
||||
}
|
||||
}
|
||||
if len(rebirthLogs) > 0 {
|
||||
bc.logsFeed.Send(rebirthLogs)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -2395,7 +2398,7 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) {
|
|||
// Run the reorg if necessary and set the given block as new head.
|
||||
start := time.Now()
|
||||
if head.ParentHash() != bc.CurrentBlock().Hash() {
|
||||
if err := bc.reorg(bc.CurrentBlock(), head); err != nil {
|
||||
if err := bc.reorg(bc.CurrentBlock(), head.Header()); err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
}
|
||||
|
|
@ -2403,11 +2406,11 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) {
|
|||
|
||||
// Emit events
|
||||
logs := bc.collectLogs(head, false)
|
||||
bc.chainFeed.Send(ChainEvent{Block: head, Hash: head.Hash(), Logs: logs})
|
||||
bc.chainFeed.Send(ChainEvent{Header: head.Header()})
|
||||
if len(logs) > 0 {
|
||||
bc.logsFeed.Send(logs)
|
||||
}
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Block: head})
|
||||
bc.chainHeadFeed.Send(ChainHeadEvent{Header: head.Header()})
|
||||
|
||||
context := []interface{}{
|
||||
"number", head.Number(),
|
||||
|
|
|
|||
|
|
@ -430,11 +430,6 @@ func (bc *BlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Su
|
|||
return bc.scope.Track(bc.chainHeadFeed.Subscribe(ch))
|
||||
}
|
||||
|
||||
// SubscribeChainSideEvent registers a subscription of ChainSideEvent.
|
||||
func (bc *BlockChain) SubscribeChainSideEvent(ch chan<- ChainSideEvent) event.Subscription {
|
||||
return bc.scope.Track(bc.chainSideFeed.Subscribe(ch))
|
||||
}
|
||||
|
||||
// SubscribeLogsEvent registers a subscription of []*types.Log.
|
||||
func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
|
||||
return bc.scope.Track(bc.logsFeed.Subscribe(ch))
|
||||
|
|
|
|||
|
|
@ -1767,7 +1767,6 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
|
|||
db, err := rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
Ephemeral: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create persistent database: %v", err)
|
||||
|
|
@ -1852,7 +1851,6 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
|
|||
db, err = rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
Ephemeral: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to reopen persistent database: %v", err)
|
||||
|
|
@ -1974,7 +1972,6 @@ func testIssue23496(t *testing.T, scheme string) {
|
|||
db, err = rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
Ephemeral: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to reopen persistent database: %v", err)
|
||||
|
|
|
|||
|
|
@ -1971,7 +1971,6 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
|
|||
db, err := rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
Ephemeral: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create persistent database: %v", err)
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
|||
db, err := rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
Ephemeral: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create persistent database: %v", err)
|
||||
|
|
@ -259,7 +258,6 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
|||
newdb, err := rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: snaptest.datadir,
|
||||
AncientsDirectory: snaptest.ancient,
|
||||
Ephemeral: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to reopen persistent database: %v", err)
|
||||
|
|
|
|||
|
|
@ -1332,85 +1332,6 @@ func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan Re
|
|||
}
|
||||
}
|
||||
|
||||
func TestReorgSideEvent(t *testing.T) {
|
||||
testReorgSideEvent(t, rawdb.HashScheme)
|
||||
testReorgSideEvent(t, rawdb.PathScheme)
|
||||
}
|
||||
|
||||
func testReorgSideEvent(t *testing.T, scheme string) {
|
||||
var (
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
gspec = &Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: types.GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}},
|
||||
}
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
)
|
||||
blockchain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
_, chain, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 3, func(i int, gen *BlockGen) {})
|
||||
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||
t.Fatalf("failed to insert chain: %v", err)
|
||||
}
|
||||
|
||||
_, replacementBlocks, _ := GenerateChainWithGenesis(gspec, ethash.NewFaker(), 4, func(i int, gen *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, gen.header.BaseFee, nil), signer, key1)
|
||||
if i == 2 {
|
||||
gen.OffsetTime(-9)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tx: %v", err)
|
||||
}
|
||||
gen.AddTx(tx)
|
||||
})
|
||||
chainSideCh := make(chan ChainSideEvent, 64)
|
||||
blockchain.SubscribeChainSideEvent(chainSideCh)
|
||||
if _, err := blockchain.InsertChain(replacementBlocks); err != nil {
|
||||
t.Fatalf("failed to insert chain: %v", err)
|
||||
}
|
||||
|
||||
expectedSideHashes := map[common.Hash]bool{
|
||||
chain[0].Hash(): true,
|
||||
chain[1].Hash(): true,
|
||||
chain[2].Hash(): true,
|
||||
}
|
||||
|
||||
i := 0
|
||||
|
||||
const timeoutDura = 10 * time.Second
|
||||
timeout := time.NewTimer(timeoutDura)
|
||||
done:
|
||||
for {
|
||||
select {
|
||||
case ev := <-chainSideCh:
|
||||
block := ev.Block
|
||||
if _, ok := expectedSideHashes[block.Hash()]; !ok {
|
||||
t.Errorf("%d: didn't expect %x to be in side chain", i, block.Hash())
|
||||
}
|
||||
i++
|
||||
|
||||
if i == len(expectedSideHashes) {
|
||||
timeout.Stop()
|
||||
|
||||
break done
|
||||
}
|
||||
timeout.Reset(timeoutDura)
|
||||
|
||||
case <-timeout.C:
|
||||
t.Fatalf("Timeout. Possibly not all blocks were triggered for sideevent: %v", i)
|
||||
}
|
||||
}
|
||||
|
||||
// make sure no more events are fired
|
||||
select {
|
||||
case e := <-chainSideCh:
|
||||
t.Errorf("unexpected event fired: %v", e)
|
||||
case <-time.After(250 * time.Millisecond):
|
||||
}
|
||||
}
|
||||
|
||||
// Tests if the canonical block can be fetched from the database during chain insertion.
|
||||
func TestCanonicalBlockRetrieval(t *testing.T) {
|
||||
testCanonicalBlockRetrieval(t, rawdb.HashScheme)
|
||||
|
|
@ -2744,7 +2665,6 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
|
|||
db, err := rawdb.Open(rawdb.OpenOptions{
|
||||
Directory: datadir,
|
||||
AncientsDirectory: ancient,
|
||||
Ephemeral: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create persistent database: %v", err)
|
||||
|
|
@ -4311,3 +4231,36 @@ func TestPragueRequests(t *testing.T) {
|
|||
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReorg(b *testing.B) {
|
||||
chainLength := b.N
|
||||
|
||||
dir := b.TempDir()
|
||||
db, err := rawdb.NewLevelDBDatabase(dir, 128, 128, "", false)
|
||||
if err != nil {
|
||||
b.Fatalf("cannot create temporary database: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
gspec := &Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: types.GenesisAlloc{benchRootAddr: {Balance: math.BigPow(2, 254)}},
|
||||
}
|
||||
blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||
defer blockchain.Stop()
|
||||
|
||||
// Insert an easy and a difficult chain afterwards
|
||||
easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), ethash.NewFaker(), db, chainLength, genValueTx(50000))
|
||||
diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), ethash.NewFaker(), db, chainLength, genValueTx(50000))
|
||||
|
||||
if _, err := blockchain.InsertChain(easyBlocks); err != nil {
|
||||
b.Fatalf("failed to insert easy chain: %v", err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
if _, err := blockchain.InsertChain(diffBlocks); err != nil {
|
||||
b.Fatalf("failed to insert difficult chain: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Master: BenchmarkReorg-8 10000 899591 ns/op 820154 B/op 1440 allocs/op 1549443072 bytes of heap used
|
||||
// WithoutOldChain: BenchmarkReorg-8 10000 1147281 ns/op 943163 B/op 1564 allocs/op 1163870208 bytes of heap used
|
||||
// WithoutNewChain: BenchmarkReorg-8 10000 1018922 ns/op 943580 B/op 1564 allocs/op 1171890176 bytes of heap used
|
||||
|
|
|
|||
|
|
@ -222,20 +222,19 @@ func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainH
|
|||
errc <- nil
|
||||
return
|
||||
}
|
||||
header := ev.Block.Header()
|
||||
if header.ParentHash != prevHash {
|
||||
if ev.Header.ParentHash != prevHash {
|
||||
// Reorg to the common ancestor if needed (might not exist in light sync mode, skip reorg then)
|
||||
// TODO(karalabe, zsfelfoldi): This seems a bit brittle, can we detect this case explicitly?
|
||||
|
||||
if rawdb.ReadCanonicalHash(c.chainDb, prevHeader.Number.Uint64()) != prevHash {
|
||||
if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, header); h != nil {
|
||||
if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, ev.Header); h != nil {
|
||||
c.newHead(h.Number.Uint64(), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
c.newHead(header.Number.Uint64(), false)
|
||||
c.newHead(ev.Header.Number.Uint64(), false)
|
||||
|
||||
prevHeader, prevHash = header, header.Hash()
|
||||
prevHeader, prevHash = ev.Header, ev.Header.Hash()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,27 +17,19 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// NewTxsEvent is posted when a batch of transactions enter the transaction pool.
|
||||
type NewTxsEvent struct{ Txs []*types.Transaction }
|
||||
|
||||
// NewMinedBlockEvent is posted when a block has been imported.
|
||||
type NewMinedBlockEvent struct{ Block *types.Block }
|
||||
|
||||
// RemovedLogsEvent is posted when a reorg happens
|
||||
type RemovedLogsEvent struct{ Logs []*types.Log }
|
||||
|
||||
type ChainEvent struct {
|
||||
Block *types.Block
|
||||
Hash common.Hash
|
||||
Logs []*types.Log
|
||||
Header *types.Header
|
||||
}
|
||||
|
||||
type ChainSideEvent struct {
|
||||
Block *types.Block
|
||||
type ChainHeadEvent struct {
|
||||
Header *types.Header
|
||||
}
|
||||
|
||||
type ChainHeadEvent struct{ Block *types.Block }
|
||||
|
|
|
|||
|
|
@ -388,10 +388,10 @@ func TestBlockReceiptStorage(t *testing.T) {
|
|||
// Insert the receipt slice into the database and check presence
|
||||
WriteReceipts(db, hash, 0, receipts)
|
||||
if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) == 0 {
|
||||
t.Fatalf("no receipts returned")
|
||||
t.Fatal("no receipts returned")
|
||||
} else {
|
||||
if err := checkReceiptsRLP(rs, receipts); err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
// Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed)
|
||||
|
|
@ -401,7 +401,7 @@ func TestBlockReceiptStorage(t *testing.T) {
|
|||
}
|
||||
// Ensure that receipts without metadata can be returned without the block body too
|
||||
if err := checkReceiptsRLP(ReadRawReceipts(db, hash, 0), receipts); err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Sanity check that body alone without the receipt is a full purge
|
||||
WriteBody(db, hash, 0, body)
|
||||
|
|
|
|||
|
|
@ -319,8 +319,8 @@ func NewLevelDBDatabase(file string, cache int, handles int, namespace string, r
|
|||
|
||||
// NewPebbleDBDatabase creates a persistent key-value database without a freezer
|
||||
// moving immutable chain segments into cold storage.
|
||||
func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly, ephemeral bool) (ethdb.Database, error) {
|
||||
db, err := pebble.New(file, cache, handles, namespace, readonly, ephemeral)
|
||||
func NewPebbleDBDatabase(file string, cache int, handles int, namespace string, readonly bool) (ethdb.Database, error) {
|
||||
db, err := pebble.New(file, cache, handles, namespace, readonly)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -358,9 +358,6 @@ type OpenOptions struct {
|
|||
Cache int // the capacity(in megabytes) of the data caching
|
||||
Handles int // number of files to be open simultaneously
|
||||
ReadOnly bool
|
||||
// Ephemeral means that filesystem sync operations should be avoided: data integrity in the face of
|
||||
// a crash is not important. This option should typically be used in tests.
|
||||
Ephemeral bool
|
||||
}
|
||||
|
||||
// openKeyValueDatabase opens a disk-based key-value database, e.g. leveldb or pebble.
|
||||
|
|
@ -382,7 +379,7 @@ func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) {
|
|||
}
|
||||
if o.Type == dbPebble || existingDb == dbPebble {
|
||||
log.Info("Using pebble as the backing database")
|
||||
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral)
|
||||
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly)
|
||||
}
|
||||
if o.Type == dbLeveldb || existingDb == dbLeveldb {
|
||||
log.Info("Using leveldb as the backing database")
|
||||
|
|
@ -390,7 +387,7 @@ func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) {
|
|||
}
|
||||
// No pre-existing database, no user-requested one either. Default to Pebble.
|
||||
log.Info("Defaulting to pebble as the backing database")
|
||||
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly, o.Ephemeral)
|
||||
return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly)
|
||||
}
|
||||
|
||||
// Open opens both a disk-based key-value database such as leveldb or pebble, but also
|
||||
|
|
|
|||
|
|
@ -282,7 +282,6 @@ func (sf *subfetcher) schedule(keys [][]byte, read bool) error {
|
|||
// Append the tasks to the current queue
|
||||
sf.lock.Lock()
|
||||
for _, key := range keys {
|
||||
key := key // closure for the append below
|
||||
sf.tasks = append(sf.tasks, &subfetcherTask{read: read, key: key})
|
||||
}
|
||||
sf.lock.Unlock()
|
||||
|
|
|
|||
|
|
@ -55,9 +55,8 @@ type VMContext struct {
|
|||
Time uint64
|
||||
Random *common.Hash
|
||||
// Effective tx gas price
|
||||
GasPrice *big.Int
|
||||
ChainConfig *params.ChainConfig
|
||||
StateDB StateDB
|
||||
GasPrice *big.Int
|
||||
StateDB StateDB
|
||||
}
|
||||
|
||||
// BlockEvent is emitted upon tracing an incoming block.
|
||||
|
|
|
|||
|
|
@ -151,9 +151,9 @@ func (indexer *txIndexer) loop(chain *BlockChain) {
|
|||
if done == nil {
|
||||
stop = make(chan struct{})
|
||||
done = make(chan struct{})
|
||||
go indexer.run(rawdb.ReadTxIndexTail(indexer.db), head.Block.NumberU64(), stop, done)
|
||||
go indexer.run(rawdb.ReadTxIndexTail(indexer.db), head.Header.Number.Uint64(), stop, done)
|
||||
}
|
||||
lastHead = head.Block.NumberU64()
|
||||
lastHead = head.Header.Number.Uint64()
|
||||
case <-done:
|
||||
stop = nil
|
||||
done = nil
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ func (p *TxPool) loop(head *types.Header, chain BlockChain) {
|
|||
select {
|
||||
case event := <-newHeadCh:
|
||||
// Chain moved forward, store the head for later consumption
|
||||
newHead = event.Block.Header()
|
||||
newHead = event.Header
|
||||
|
||||
case head := <-resetDone:
|
||||
// Previous reset finished, update the old head and allow a new reset
|
||||
|
|
|
|||
|
|
@ -546,9 +546,7 @@ func TestYParityJSONUnmarshalling(t *testing.T) {
|
|||
DynamicFeeTxType,
|
||||
BlobTxType,
|
||||
} {
|
||||
txType := txType
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(fmt.Sprintf("txType=%d: %s", txType, test.name), func(t *testing.T) {
|
||||
// Copy the base json
|
||||
testJson := maps.Clone(baseJson)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ func (e ErrStackUnderflow) Error() string {
|
|||
}
|
||||
|
||||
func (e ErrStackUnderflow) Unwrap() error {
|
||||
return fmt.Errorf("stack underflow")
|
||||
return errors.New("stack underflow")
|
||||
}
|
||||
|
||||
// ErrStackOverflow wraps an evm error when the items on the stack exceeds
|
||||
|
|
@ -71,7 +71,7 @@ func (e ErrStackOverflow) Error() string {
|
|||
}
|
||||
|
||||
func (e ErrStackOverflow) Unwrap() error {
|
||||
return fmt.Errorf("stack overflow")
|
||||
return errors.New("stack overflow")
|
||||
}
|
||||
|
||||
// ErrInvalidOpCode wraps an evm error when an invalid opcode is encountered.
|
||||
|
|
|
|||
|
|
@ -613,7 +613,6 @@ func (evm *EVM) GetVMContext() *tracing.VMContext {
|
|||
Time: evm.Context.Time,
|
||||
Random: evm.Context.Random,
|
||||
GasPrice: evm.TxContext.GasPrice,
|
||||
ChainConfig: evm.ChainConfig(),
|
||||
StateDB: evm.StateDB,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
|
|||
cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||
cfg.GasLimit = gas
|
||||
if len(tracerCode) > 0 {
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil)
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil, cfg.ChainConfig)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
|
@ -887,7 +887,7 @@ func TestRuntimeJSTracer(t *testing.T) {
|
|||
statedb.SetCode(common.HexToAddress("0xee"), calleeCode)
|
||||
statedb.SetCode(common.HexToAddress("0xff"), suicideCode)
|
||||
|
||||
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
|
||||
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil, params.MergedTestChainConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -922,7 +922,7 @@ func TestJSTracerCreateTx(t *testing.T) {
|
|||
code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)}
|
||||
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
|
||||
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil, params.MergedTestChainConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
btc_ecdsa "github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
decred_ecdsa "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
|
||||
)
|
||||
|
||||
// Ecrecover returns the uncompressed public key that created the given signature.
|
||||
|
|
@ -39,16 +39,16 @@ func Ecrecover(hash, sig []byte) ([]byte, error) {
|
|||
return bytes, err
|
||||
}
|
||||
|
||||
func sigToPub(hash, sig []byte) (*btcec.PublicKey, error) {
|
||||
func sigToPub(hash, sig []byte) (*secp256k1.PublicKey, error) {
|
||||
if len(sig) != SignatureLength {
|
||||
return nil, errors.New("invalid signature")
|
||||
}
|
||||
// Convert to btcec input format with 'recovery id' v at the beginning.
|
||||
// Convert to secp256k1 input format with 'recovery id' v at the beginning.
|
||||
btcsig := make([]byte, SignatureLength)
|
||||
btcsig[0] = sig[RecoveryIDOffset] + 27
|
||||
copy(btcsig[1:], sig)
|
||||
|
||||
pub, _, err := btc_ecdsa.RecoverCompact(btcsig, hash)
|
||||
pub, _, err := decred_ecdsa.RecoverCompact(btcsig, hash)
|
||||
return pub, err
|
||||
}
|
||||
|
||||
|
|
@ -82,13 +82,13 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
|
|||
if prv.Curve != S256() {
|
||||
return nil, errors.New("private key curve is not secp256k1")
|
||||
}
|
||||
// ecdsa.PrivateKey -> btcec.PrivateKey
|
||||
var priv btcec.PrivateKey
|
||||
// ecdsa.PrivateKey -> secp256k1.PrivateKey
|
||||
var priv secp256k1.PrivateKey
|
||||
if overflow := priv.Key.SetByteSlice(prv.D.Bytes()); overflow || priv.Key.IsZero() {
|
||||
return nil, errors.New("invalid private key")
|
||||
}
|
||||
defer priv.Zero()
|
||||
sig := btc_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey
|
||||
sig := decred_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey
|
||||
// Convert to Ethereum signature format with 'recovery id' v at the end.
|
||||
v := sig[0] - 27
|
||||
copy(sig, sig[1:])
|
||||
|
|
@ -103,19 +103,19 @@ func VerifySignature(pubkey, hash, signature []byte) bool {
|
|||
if len(signature) != 64 {
|
||||
return false
|
||||
}
|
||||
var r, s btcec.ModNScalar
|
||||
var r, s secp256k1.ModNScalar
|
||||
if r.SetByteSlice(signature[:32]) {
|
||||
return false // overflow
|
||||
}
|
||||
if s.SetByteSlice(signature[32:]) {
|
||||
return false
|
||||
}
|
||||
sig := btc_ecdsa.NewSignature(&r, &s)
|
||||
key, err := btcec.ParsePubKey(pubkey)
|
||||
sig := decred_ecdsa.NewSignature(&r, &s)
|
||||
key, err := secp256k1.ParsePubKey(pubkey)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// Reject malleable signatures. libsecp256k1 does this check but btcec doesn't.
|
||||
// Reject malleable signatures. libsecp256k1 does this check but decred doesn't.
|
||||
if s.IsOverHalfOrder() {
|
||||
return false
|
||||
}
|
||||
|
|
@ -127,7 +127,7 @@ func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
|
|||
if len(pubkey) != 33 {
|
||||
return nil, errors.New("invalid compressed public key length")
|
||||
}
|
||||
key, err := btcec.ParsePubKey(pubkey)
|
||||
key, err := secp256k1.ParsePubKey(pubkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -148,20 +148,20 @@ func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
|
|||
// when constructing a PrivateKey.
|
||||
func CompressPubkey(pubkey *ecdsa.PublicKey) []byte {
|
||||
// NOTE: the coordinates may be validated with
|
||||
// btcec.ParsePubKey(FromECDSAPub(pubkey))
|
||||
var x, y btcec.FieldVal
|
||||
// secp256k1.ParsePubKey(FromECDSAPub(pubkey))
|
||||
var x, y secp256k1.FieldVal
|
||||
x.SetByteSlice(pubkey.X.Bytes())
|
||||
y.SetByteSlice(pubkey.Y.Bytes())
|
||||
return btcec.NewPublicKey(&x, &y).SerializeCompressed()
|
||||
return secp256k1.NewPublicKey(&x, &y).SerializeCompressed()
|
||||
}
|
||||
|
||||
// S256 returns an instance of the secp256k1 curve.
|
||||
func S256() EllipticCurve {
|
||||
return btCurve{btcec.S256()}
|
||||
return btCurve{secp256k1.S256()}
|
||||
}
|
||||
|
||||
type btCurve struct {
|
||||
*btcec.KoblitzCurve
|
||||
*secp256k1.KoblitzCurve
|
||||
}
|
||||
|
||||
// Marshal converts a point given as (x, y) into a byte slice.
|
||||
|
|
|
|||
|
|
@ -275,10 +275,6 @@ func (b *EthAPIBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) e
|
|||
return b.eth.BlockChain().SubscribeChainHeadEvent(ch)
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
|
||||
return b.eth.BlockChain().SubscribeChainSideEvent(ch)
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
|
||||
return b.eth.BlockChain().SubscribeLogsEvent(ch)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
}
|
||||
)
|
||||
if config.VMTrace != "" {
|
||||
var traceConfig json.RawMessage
|
||||
traceConfig := json.RawMessage("{}")
|
||||
if config.VMTraceJsonConfig != "" {
|
||||
traceConfig = json.RawMessage(config.VMTraceJsonConfig)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1600,7 +1600,7 @@ func TestBlockToPayloadWithBlobs(t *testing.T) {
|
|||
}
|
||||
|
||||
block := types.NewBlock(&header, &types.Body{Transactions: txs}, nil, trie.NewStackTrie(nil))
|
||||
envelope := engine.BlockToExecutableData(block, nil, sidecars)
|
||||
envelope := engine.BlockToExecutableData(block, nil, sidecars, nil)
|
||||
var want int
|
||||
for _, tx := range txs {
|
||||
want += len(tx.BlobHashes())
|
||||
|
|
|
|||
|
|
@ -123,16 +123,16 @@ func TestSimulatedBeaconSendWithdrawals(t *testing.T) {
|
|||
timer := time.NewTimer(12 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case evt := <-chainHeadCh:
|
||||
for _, includedTx := range evt.Block.Transactions() {
|
||||
case ev := <-chainHeadCh:
|
||||
block := ethService.BlockChain().GetBlock(ev.Header.Hash(), ev.Header.Number.Uint64())
|
||||
for _, includedTx := range block.Transactions() {
|
||||
includedTxs[includedTx.Hash()] = struct{}{}
|
||||
}
|
||||
for _, includedWithdrawal := range evt.Block.Withdrawals() {
|
||||
for _, includedWithdrawal := range block.Withdrawals() {
|
||||
includedWithdrawals = append(includedWithdrawals, includedWithdrawal.Index)
|
||||
}
|
||||
|
||||
// ensure all withdrawals/txs included. this will take two blocks b/c number of withdrawals > 10
|
||||
if len(includedTxs) == len(txs) && len(includedWithdrawals) == len(withdrawals) && evt.Block.Number().Cmp(big.NewInt(2)) == 0 {
|
||||
if len(includedTxs) == len(txs) && len(includedWithdrawals) == len(withdrawals) && ev.Header.Number.Cmp(big.NewInt(2)) == 0 {
|
||||
return
|
||||
}
|
||||
case <-timer.C:
|
||||
|
|
@ -186,11 +186,12 @@ func TestOnDemandSpam(t *testing.T) {
|
|||
)
|
||||
for {
|
||||
select {
|
||||
case evt := <-chainHeadCh:
|
||||
for _, itx := range evt.Block.Transactions() {
|
||||
case ev := <-chainHeadCh:
|
||||
block := eth.BlockChain().GetBlock(ev.Header.Hash(), ev.Header.Number.Uint64())
|
||||
for _, itx := range block.Transactions() {
|
||||
includedTxs[itx.Hash()] = struct{}{}
|
||||
}
|
||||
for _, iwx := range evt.Block.Withdrawals() {
|
||||
for _, iwx := range block.Withdrawals() {
|
||||
includedWxs = append(includedWxs, iwx.Index)
|
||||
}
|
||||
// ensure all withdrawals/txs included. this will take two blocks b/c number of withdrawals > 10
|
||||
|
|
|
|||
|
|
@ -541,7 +541,6 @@ func (d *Downloader) spawnSync(fetchers []func() error) error {
|
|||
errc := make(chan error, len(fetchers))
|
||||
d.cancelWg.Add(len(fetchers))
|
||||
for _, fn := range fetchers {
|
||||
fn := fn
|
||||
go func() { defer d.cancelWg.Done(); errc <- fn() }()
|
||||
}
|
||||
// Wait for the first error, then terminate the others.
|
||||
|
|
|
|||
|
|
@ -273,7 +273,6 @@ func (api *FilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subsc
|
|||
select {
|
||||
case logs := <-matchedLogs:
|
||||
for _, log := range logs {
|
||||
log := log
|
||||
notifier.Notify(rpcSub.ID, &log)
|
||||
}
|
||||
case <-rpcSub.Err(): // client send an unsubscribe request
|
||||
|
|
|
|||
|
|
@ -391,7 +391,7 @@ func (es *EventSystem) handleTxsEvent(filters filterIndex, ev core.NewTxsEvent)
|
|||
|
||||
func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent) {
|
||||
for _, f := range filters[BlocksSubscription] {
|
||||
f.headers <- ev.Block.Header()
|
||||
f.headers <- ev.Header
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ func TestBlockSubscription(t *testing.T) {
|
|||
)
|
||||
|
||||
for _, blk := range chain {
|
||||
chainEvents = append(chainEvents, core.ChainEvent{Hash: blk.Hash(), Block: blk})
|
||||
chainEvents = append(chainEvents, core.ChainEvent{Header: blk.Header()})
|
||||
}
|
||||
|
||||
chan0 := make(chan *types.Header)
|
||||
|
|
@ -213,13 +213,13 @@ func TestBlockSubscription(t *testing.T) {
|
|||
for i1 != len(chainEvents) || i2 != len(chainEvents) {
|
||||
select {
|
||||
case header := <-chan0:
|
||||
if chainEvents[i1].Hash != header.Hash() {
|
||||
t.Errorf("sub0 received invalid hash on index %d, want %x, got %x", i1, chainEvents[i1].Hash, header.Hash())
|
||||
if chainEvents[i1].Header.Hash() != header.Hash() {
|
||||
t.Errorf("sub0 received invalid hash on index %d, want %x, got %x", i1, chainEvents[i1].Header.Hash(), header.Hash())
|
||||
}
|
||||
i1++
|
||||
case header := <-chan1:
|
||||
if chainEvents[i2].Hash != header.Hash() {
|
||||
t.Errorf("sub1 received invalid hash on index %d, want %x, got %x", i2, chainEvents[i2].Hash, header.Hash())
|
||||
if chainEvents[i2].Header.Hash() != header.Hash() {
|
||||
t.Errorf("sub1 received invalid hash on index %d, want %x, got %x", i2, chainEvents[i2].Header.Hash(), header.Hash())
|
||||
}
|
||||
i2++
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,10 +124,10 @@ func NewOracle(backend OracleBackend, params Config, startPrice *big.Int) *Oracl
|
|||
go func() {
|
||||
var lastHead common.Hash
|
||||
for ev := range headEvent {
|
||||
if ev.Block.ParentHash() != lastHead {
|
||||
if ev.Header.ParentHash != lastHead {
|
||||
cache.Purge()
|
||||
}
|
||||
lastHead = ev.Block.Hash()
|
||||
lastHead = ev.Header.Hash()
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
|||
|
|
@ -390,8 +390,6 @@ func testTransactionPropagation(t *testing.T, protocol uint) {
|
|||
}
|
||||
// Interconnect all the sink handlers with the source handler
|
||||
for i, sink := range sinks {
|
||||
sink := sink // Closure for goroutine below
|
||||
|
||||
sourcePipe, sinkPipe := p2p.MsgPipe()
|
||||
defer sourcePipe.Close()
|
||||
defer sinkPipe.Close()
|
||||
|
|
|
|||
|
|
@ -93,8 +93,6 @@ type TxPool interface {
|
|||
func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2p.Protocol {
|
||||
protocols := make([]p2p.Protocol, 0, len(ProtocolVersions))
|
||||
for _, version := range ProtocolVersions {
|
||||
version := version // Closure
|
||||
|
||||
protocols = append(protocols, p2p.Protocol{
|
||||
Name: ProtocolName,
|
||||
Version: version,
|
||||
|
|
|
|||
|
|
@ -85,8 +85,6 @@ type Backend interface {
|
|||
func MakeProtocols(backend Backend) []p2p.Protocol {
|
||||
protocols := make([]p2p.Protocol, len(ProtocolVersions))
|
||||
for i, version := range ProtocolVersions {
|
||||
version := version // Closure
|
||||
|
||||
protocols[i] = p2p.Protocol{
|
||||
Name: ProtocolName,
|
||||
Version: version,
|
||||
|
|
|
|||
|
|
@ -345,7 +345,6 @@ func (task *accountTask) activeSubTasks() map[common.Hash][]*storageTask {
|
|||
last = task.res.hashes[len(task.res.hashes)-1]
|
||||
)
|
||||
for hash, subTasks := range task.SubTasks {
|
||||
subTasks := subTasks // closure
|
||||
if hash.Cmp(last) <= 0 {
|
||||
tasks[hash] = subTasks
|
||||
}
|
||||
|
|
@ -765,8 +764,6 @@ func (s *Syncer) loadSyncStatus() {
|
|||
}
|
||||
s.tasks = progress.Tasks
|
||||
for _, task := range s.tasks {
|
||||
task := task // closure for task.genBatch in the stacktrie writer callback
|
||||
|
||||
// Restore the completed storages
|
||||
task.stateCompleted = make(map[common.Hash]struct{})
|
||||
for _, hash := range task.StorageCompleted {
|
||||
|
|
@ -790,8 +787,6 @@ func (s *Syncer) loadSyncStatus() {
|
|||
// Restore leftover storage tasks
|
||||
for accountHash, subtasks := range task.SubTasks {
|
||||
for _, subtask := range subtasks {
|
||||
subtask := subtask // closure for subtask.genBatch in the stacktrie writer callback
|
||||
|
||||
subtask.genBatch = ethdb.HookedBatch{
|
||||
Batch: s.db.NewBatch(),
|
||||
OnPut: func(key []byte, value []byte) {
|
||||
|
|
|
|||
|
|
@ -1011,7 +1011,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
|
|||
Stop: logger.Stop,
|
||||
}
|
||||
} else {
|
||||
tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
|
||||
tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig, api.backend.ChainConfig())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// Context contains some contextual infos for a transaction execution that is not
|
||||
|
|
@ -44,8 +45,8 @@ type Tracer struct {
|
|||
Stop func(err error)
|
||||
}
|
||||
|
||||
type ctorFn func(*Context, json.RawMessage) (*Tracer, error)
|
||||
type jsCtorFn func(string, *Context, json.RawMessage) (*Tracer, error)
|
||||
type ctorFn func(*Context, json.RawMessage, *params.ChainConfig) (*Tracer, error)
|
||||
type jsCtorFn func(string, *Context, json.RawMessage, *params.ChainConfig) (*Tracer, error)
|
||||
|
||||
type elem struct {
|
||||
ctor ctorFn
|
||||
|
|
@ -78,12 +79,15 @@ func (d *directory) RegisterJSEval(f jsCtorFn) {
|
|||
// New returns a new instance of a tracer, by iterating through the
|
||||
// registered lookups. Name is either name of an existing tracer
|
||||
// or an arbitrary JS code.
|
||||
func (d *directory) New(name string, ctx *Context, cfg json.RawMessage) (*Tracer, error) {
|
||||
func (d *directory) New(name string, ctx *Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*Tracer, error) {
|
||||
if len(cfg) == 0 {
|
||||
cfg = json.RawMessage("{}")
|
||||
}
|
||||
if elem, ok := d.elems[name]; ok {
|
||||
return elem.ctor(ctx, cfg)
|
||||
return elem.ctor(ctx, cfg, chainConfig)
|
||||
}
|
||||
// Assume JS code
|
||||
return d.jsEval(name, ctx, cfg)
|
||||
return d.jsEval(name, ctx, cfg, chainConfig)
|
||||
}
|
||||
|
||||
// IsJS will return true if the given tracer will evaluate
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
if !strings.HasSuffix(file.Name(), ".json") {
|
||||
continue
|
||||
}
|
||||
file := file // capture range variable
|
||||
t.Run(camel(strings.TrimSuffix(file.Name(), ".json")), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
@ -121,7 +120,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
)
|
||||
state.Close()
|
||||
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
|
@ -183,7 +182,6 @@ func BenchmarkTracers(b *testing.B) {
|
|||
if !strings.HasSuffix(file.Name(), ".json") {
|
||||
continue
|
||||
}
|
||||
file := file // capture range variable
|
||||
b.Run(camel(strings.TrimSuffix(file.Name(), ".json")), func(b *testing.B) {
|
||||
blob, err := os.ReadFile(filepath.Join("testdata", "call_tracer", file.Name()))
|
||||
if err != nil {
|
||||
|
|
@ -229,7 +227,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
|
|||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil)
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config)
|
||||
if err != nil {
|
||||
b.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
|
@ -266,7 +264,7 @@ func TestInternals(t *testing.T) {
|
|||
}
|
||||
)
|
||||
mkTracer := func(name string, cfg json.RawMessage) *tracers.Tracer {
|
||||
tr, err := tracers.DefaultDirectory.New(name, nil, cfg)
|
||||
tr, err := tracers.DefaultDirectory.New(name, nil, cfg, config)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
|
|||
defer state.Close()
|
||||
|
||||
// Create the tracer, the EVM environment and run it
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
|
@ -151,7 +151,6 @@ func testFlatCallTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
if !strings.HasSuffix(file.Name(), ".json") {
|
||||
continue
|
||||
}
|
||||
file := file // capture range variable
|
||||
t.Run(camel(strings.TrimSuffix(file.Name(), ".json")), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
if !strings.HasSuffix(file.Name(), ".json") {
|
||||
continue
|
||||
}
|
||||
file := file // capture range variable
|
||||
t.Run(camel(strings.TrimSuffix(file.Name(), ".json")), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
@ -98,7 +97,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
)
|
||||
defer state.Close()
|
||||
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
|
||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/internal"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/holiman/uint256"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -46,10 +47,10 @@ func init() {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
type ctorFn = func(*tracers.Context, json.RawMessage) (*tracers.Tracer, error)
|
||||
type ctorFn = func(*tracers.Context, json.RawMessage, *params.ChainConfig) (*tracers.Tracer, error)
|
||||
lookup := func(code string) ctorFn {
|
||||
return func(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
|
||||
return newJsTracer(code, ctx, cfg)
|
||||
return func(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
|
||||
return newJsTracer(code, ctx, cfg, chainConfig)
|
||||
}
|
||||
}
|
||||
for name, code := range assetTracers {
|
||||
|
|
@ -102,6 +103,7 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b
|
|||
type jsTracer struct {
|
||||
vm *goja.Runtime
|
||||
env *tracing.VMContext
|
||||
chainConfig *params.ChainConfig
|
||||
toBig toBigFn // Converts a hex string into a JS bigint
|
||||
toBuf toBufFn // Converts a []byte into a JS buffer
|
||||
fromBuf fromBufFn // Converts an array, hex string or Uint8Array to a []byte
|
||||
|
|
@ -138,13 +140,14 @@ type jsTracer struct {
|
|||
// The methods `result` and `fault` are required to be present.
|
||||
// The methods `step`, `enter`, and `exit` are optional, but note that
|
||||
// `enter` and `exit` always go together.
|
||||
func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
|
||||
func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
|
||||
vm := goja.New()
|
||||
// By default field names are exported to JS as is, i.e. capitalized.
|
||||
vm.SetFieldNameMapper(goja.UncapFieldNameMapper())
|
||||
t := &jsTracer{
|
||||
vm: vm,
|
||||
ctx: make(map[string]goja.Value),
|
||||
vm: vm,
|
||||
ctx: make(map[string]goja.Value),
|
||||
chainConfig: chainConfig,
|
||||
}
|
||||
|
||||
t.setTypeConverters()
|
||||
|
|
@ -244,7 +247,7 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from
|
|||
db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf}
|
||||
t.dbValue = db.setupObject()
|
||||
// Update list of precompiles based on current block
|
||||
rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time)
|
||||
rules := t.chainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time)
|
||||
t.activePrecompiles = vm.ActivePrecompiles(rules)
|
||||
t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64())
|
||||
t.ctx["gas"] = t.vm.ToValue(tx.Gas())
|
||||
|
|
|
|||
|
|
@ -90,11 +90,12 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo
|
|||
func TestTracer(t *testing.T) {
|
||||
execTracer := func(code string, contract []byte) ([]byte, string) {
|
||||
t.Helper()
|
||||
tracer, err := newJsTracer(code, nil, nil)
|
||||
chainConfig := params.TestChainConfig
|
||||
tracer, err := newJsTracer(code, nil, nil, chainConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ret, err := runTrace(tracer, testCtx(), params.TestChainConfig, contract)
|
||||
ret, err := runTrace(tracer, testCtx(), chainConfig, contract)
|
||||
if err != nil {
|
||||
return nil, err.Error() // Stringify to allow comparison without nil checks
|
||||
}
|
||||
|
|
@ -167,7 +168,8 @@ func TestTracer(t *testing.T) {
|
|||
|
||||
func TestHalt(t *testing.T) {
|
||||
timeout := errors.New("stahp")
|
||||
tracer, err := newJsTracer("{step: function() { while(1); }, result: function() { return null; }, fault: function(){}}", nil, nil)
|
||||
chainConfig := params.TestChainConfig
|
||||
tracer, err := newJsTracer("{step: function() { while(1); }, result: function() { return null; }, fault: function(){}}", nil, nil, chainConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -175,20 +177,21 @@ func TestHalt(t *testing.T) {
|
|||
time.Sleep(1 * time.Second)
|
||||
tracer.Stop(timeout)
|
||||
}()
|
||||
if _, err = runTrace(tracer, testCtx(), params.TestChainConfig, nil); !strings.Contains(err.Error(), "stahp") {
|
||||
if _, err = runTrace(tracer, testCtx(), chainConfig, nil); !strings.Contains(err.Error(), "stahp") {
|
||||
t.Errorf("Expected timeout error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHaltBetweenSteps(t *testing.T) {
|
||||
tracer, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }}", nil, nil)
|
||||
chainConfig := params.TestChainConfig
|
||||
tracer, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }}", nil, nil, chainConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
scope := &vm.ScopeContext{
|
||||
Contract: vm.NewContract(&account{}, &account{}, uint256.NewInt(0), 0),
|
||||
}
|
||||
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.Hooks})
|
||||
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, chainConfig, vm.Config{Tracer: tracer.Hooks})
|
||||
tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{})
|
||||
tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 0, big.NewInt(0))
|
||||
tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil)
|
||||
|
|
@ -206,11 +209,12 @@ func TestHaltBetweenSteps(t *testing.T) {
|
|||
func TestNoStepExec(t *testing.T) {
|
||||
execTracer := func(code string) []byte {
|
||||
t.Helper()
|
||||
tracer, err := newJsTracer(code, nil, nil)
|
||||
chainConfig := params.TestChainConfig
|
||||
tracer, err := newJsTracer(code, nil, nil, chainConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.Hooks})
|
||||
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, chainConfig, vm.Config{Tracer: tracer.Hooks})
|
||||
tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{})
|
||||
tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 1000, big.NewInt(0))
|
||||
tracer.OnExit(0, nil, 0, nil, false)
|
||||
|
|
@ -241,7 +245,7 @@ func TestIsPrecompile(t *testing.T) {
|
|||
chaincfg.IstanbulBlock = big.NewInt(200)
|
||||
chaincfg.BerlinBlock = big.NewInt(300)
|
||||
txCtx := vm.TxContext{GasPrice: big.NewInt(100000)}
|
||||
tracer, err := newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil)
|
||||
tracer, err := newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil, chaincfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -255,7 +259,7 @@ func TestIsPrecompile(t *testing.T) {
|
|||
t.Errorf("tracer should not consider blake2f as precompile in byzantium")
|
||||
}
|
||||
|
||||
tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil)
|
||||
tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil, chaincfg)
|
||||
blockCtx = vm.BlockContext{BlockNumber: big.NewInt(250)}
|
||||
res, err = runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg, nil)
|
||||
if err != nil {
|
||||
|
|
@ -267,15 +271,16 @@ func TestIsPrecompile(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestEnterExit(t *testing.T) {
|
||||
chainConfig := params.TestChainConfig
|
||||
// test that either both or none of enter() and exit() are defined
|
||||
if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context), nil); err == nil {
|
||||
if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context), nil, chainConfig); err == nil {
|
||||
t.Fatal("tracer creation should've failed without exit() definition")
|
||||
}
|
||||
if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context), nil); err != nil {
|
||||
if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context), nil, chainConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// test that the enter and exit method are correctly invoked and the values passed
|
||||
tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context), nil)
|
||||
tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context), nil, chainConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -297,7 +302,8 @@ func TestEnterExit(t *testing.T) {
|
|||
|
||||
func TestSetup(t *testing.T) {
|
||||
// Test empty config
|
||||
_, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(tracers.Context), nil)
|
||||
chainConfig := params.TestChainConfig
|
||||
_, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(tracers.Context), nil, chainConfig)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
|
@ -307,12 +313,12 @@ func TestSetup(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
// Test no setup func
|
||||
_, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(tracers.Context), cfg)
|
||||
_, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(tracers.Context), cfg, chainConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Test config value
|
||||
tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(tracers.Context), cfg)
|
||||
tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(tracers.Context), cfg, chainConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,19 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package tracers
|
||||
|
||||
import (
|
||||
|
|
@ -24,6 +40,9 @@ func (d *liveDirectory) Register(name string, f ctorFunc) {
|
|||
|
||||
// New instantiates a tracer by name.
|
||||
func (d *liveDirectory) New(name string, config json.RawMessage) (*tracing.Hooks, error) {
|
||||
if len(config) == 0 {
|
||||
config = json.RawMessage("{}")
|
||||
}
|
||||
if f, ok := d.elems[name]; ok {
|
||||
return f(config)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,19 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package live
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,19 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package live
|
||||
|
||||
import (
|
||||
|
|
@ -19,7 +35,7 @@ import (
|
|||
)
|
||||
|
||||
func init() {
|
||||
tracers.LiveDirectory.Register("supply", newSupply)
|
||||
tracers.LiveDirectory.Register("supply", newSupplyTracer)
|
||||
}
|
||||
|
||||
type supplyInfoIssuance struct {
|
||||
|
|
@ -63,7 +79,7 @@ type supplyTxCallstack struct {
|
|||
burn *big.Int
|
||||
}
|
||||
|
||||
type supply struct {
|
||||
type supplyTracer struct {
|
||||
delta supplyInfo
|
||||
txCallstack []supplyTxCallstack // Callstack for current transaction
|
||||
logger *lumberjack.Logger
|
||||
|
|
@ -74,12 +90,10 @@ type supplyTracerConfig struct {
|
|||
MaxSize int `json:"maxSize"` // MaxSize is the maximum size in megabytes of the tracer log file before it gets rotated. It defaults to 100 megabytes.
|
||||
}
|
||||
|
||||
func newSupply(cfg json.RawMessage) (*tracing.Hooks, error) {
|
||||
func newSupplyTracer(cfg json.RawMessage) (*tracing.Hooks, error) {
|
||||
var config supplyTracerConfig
|
||||
if cfg != nil {
|
||||
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse config: %v", err)
|
||||
}
|
||||
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse config: %v", err)
|
||||
}
|
||||
if config.Path == "" {
|
||||
return nil, errors.New("supply tracer output path is required")
|
||||
|
|
@ -93,19 +107,19 @@ func newSupply(cfg json.RawMessage) (*tracing.Hooks, error) {
|
|||
logger.MaxSize = config.MaxSize
|
||||
}
|
||||
|
||||
t := &supply{
|
||||
t := &supplyTracer{
|
||||
delta: newSupplyInfo(),
|
||||
logger: logger,
|
||||
}
|
||||
return &tracing.Hooks{
|
||||
OnBlockStart: t.OnBlockStart,
|
||||
OnBlockEnd: t.OnBlockEnd,
|
||||
OnGenesisBlock: t.OnGenesisBlock,
|
||||
OnTxStart: t.OnTxStart,
|
||||
OnBalanceChange: t.OnBalanceChange,
|
||||
OnEnter: t.OnEnter,
|
||||
OnExit: t.OnExit,
|
||||
OnClose: t.OnClose,
|
||||
OnBlockStart: t.onBlockStart,
|
||||
OnBlockEnd: t.onBlockEnd,
|
||||
OnGenesisBlock: t.onGenesisBlock,
|
||||
OnTxStart: t.onTxStart,
|
||||
OnBalanceChange: t.onBalanceChange,
|
||||
OnEnter: t.onEnter,
|
||||
OnExit: t.onExit,
|
||||
OnClose: t.onClose,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -128,11 +142,11 @@ func newSupplyInfo() supplyInfo {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *supply) resetDelta() {
|
||||
func (s *supplyTracer) resetDelta() {
|
||||
s.delta = newSupplyInfo()
|
||||
}
|
||||
|
||||
func (s *supply) OnBlockStart(ev tracing.BlockEvent) {
|
||||
func (s *supplyTracer) onBlockStart(ev tracing.BlockEvent) {
|
||||
s.resetDelta()
|
||||
|
||||
s.delta.Number = ev.Block.NumberU64()
|
||||
|
|
@ -155,11 +169,11 @@ func (s *supply) OnBlockStart(ev tracing.BlockEvent) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *supply) OnBlockEnd(err error) {
|
||||
func (s *supplyTracer) onBlockEnd(err error) {
|
||||
s.write(s.delta)
|
||||
}
|
||||
|
||||
func (s *supply) OnGenesisBlock(b *types.Block, alloc types.GenesisAlloc) {
|
||||
func (s *supplyTracer) onGenesisBlock(b *types.Block, alloc types.GenesisAlloc) {
|
||||
s.resetDelta()
|
||||
|
||||
s.delta.Number = b.NumberU64()
|
||||
|
|
@ -174,7 +188,7 @@ func (s *supply) OnGenesisBlock(b *types.Block, alloc types.GenesisAlloc) {
|
|||
s.write(s.delta)
|
||||
}
|
||||
|
||||
func (s *supply) OnBalanceChange(a common.Address, prevBalance, newBalance *big.Int, reason tracing.BalanceChangeReason) {
|
||||
func (s *supplyTracer) onBalanceChange(a common.Address, prevBalance, newBalance *big.Int, reason tracing.BalanceChangeReason) {
|
||||
diff := new(big.Int).Sub(newBalance, prevBalance)
|
||||
|
||||
// NOTE: don't handle "BalanceIncreaseGenesisBalance" because it is handled in OnGenesisBlock
|
||||
|
|
@ -193,12 +207,12 @@ func (s *supply) OnBalanceChange(a common.Address, prevBalance, newBalance *big.
|
|||
}
|
||||
}
|
||||
|
||||
func (s *supply) OnTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) {
|
||||
func (s *supplyTracer) onTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) {
|
||||
s.txCallstack = make([]supplyTxCallstack, 0, 1)
|
||||
}
|
||||
|
||||
// internalTxsHandler handles internal transactions burned amount
|
||||
func (s *supply) internalTxsHandler(call *supplyTxCallstack) {
|
||||
func (s *supplyTracer) internalTxsHandler(call *supplyTxCallstack) {
|
||||
// Handle Burned amount
|
||||
if call.burn != nil {
|
||||
s.delta.Burn.Misc.Add(s.delta.Burn.Misc, call.burn)
|
||||
|
|
@ -211,7 +225,7 @@ func (s *supply) internalTxsHandler(call *supplyTxCallstack) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *supply) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
func (s *supplyTracer) onEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
call := supplyTxCallstack{
|
||||
calls: make([]supplyTxCallstack, 0),
|
||||
}
|
||||
|
|
@ -226,7 +240,7 @@ func (s *supply) OnEnter(depth int, typ byte, from common.Address, to common.Add
|
|||
s.txCallstack = append(s.txCallstack, call)
|
||||
}
|
||||
|
||||
func (s *supply) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
func (s *supplyTracer) onExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
if depth == 0 {
|
||||
// No need to handle Burned amount if transaction is reverted
|
||||
if !reverted {
|
||||
|
|
@ -252,13 +266,13 @@ func (s *supply) OnExit(depth int, output []byte, gasUsed uint64, err error, rev
|
|||
s.txCallstack[size-1].calls = append(s.txCallstack[size-1].calls, call)
|
||||
}
|
||||
|
||||
func (s *supply) OnClose() {
|
||||
func (s *supplyTracer) onClose() {
|
||||
if err := s.logger.Close(); err != nil {
|
||||
log.Warn("failed to close supply tracer log file", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *supply) write(data any) {
|
||||
func (s *supplyTracer) write(data any) {
|
||||
supply, ok := data.(supplyInfo)
|
||||
if !ok {
|
||||
log.Warn("failed to cast supply tracer data on write to log file")
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ func formatLogs(logs []StructLog) []StructLogRes {
|
|||
}
|
||||
formatted[index].Stack = &stack
|
||||
}
|
||||
if trace.ReturnData != nil && len(trace.ReturnData) > 0 {
|
||||
if len(trace.ReturnData) > 0 {
|
||||
formatted[index].ReturnData = hexutil.Bytes(trace.ReturnData).String()
|
||||
}
|
||||
if trace.Memory != nil {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
@ -48,17 +49,19 @@ func init() {
|
|||
// 0xc281d19e-0: 1
|
||||
// }
|
||||
type fourByteTracer struct {
|
||||
ids map[string]int // ids aggregates the 4byte ids found
|
||||
interrupt atomic.Bool // Atomic flag to signal execution interruption
|
||||
reason error // Textual reason for the interruption
|
||||
ids map[string]int // ids aggregates the 4byte ids found
|
||||
interrupt atomic.Bool // Atomic flag to signal execution interruption
|
||||
reason error // Textual reason for the interruption
|
||||
chainConfig *params.ChainConfig
|
||||
activePrecompiles []common.Address // Updated on tx start based on given rules
|
||||
}
|
||||
|
||||
// newFourByteTracer returns a native go tracer which collects
|
||||
// 4 byte-identifiers of a tx, and implements vm.EVMLogger.
|
||||
func newFourByteTracer(ctx *tracers.Context, _ json.RawMessage) (*tracers.Tracer, error) {
|
||||
func newFourByteTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
|
||||
t := &fourByteTracer{
|
||||
ids: make(map[string]int),
|
||||
ids: make(map[string]int),
|
||||
chainConfig: chainConfig,
|
||||
}
|
||||
return &tracers.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
|
|
@ -88,7 +91,7 @@ func (t *fourByteTracer) store(id []byte, size int) {
|
|||
|
||||
func (t *fourByteTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
|
||||
// Update list of precompiles based on current block
|
||||
rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time)
|
||||
rules := t.chainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time)
|
||||
t.activePrecompiles = vm.ActivePrecompiles(rules)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go
|
||||
|
|
@ -125,7 +126,7 @@ type callTracerConfig struct {
|
|||
|
||||
// newCallTracer returns a native go tracer which tracks
|
||||
// call frames of a tx, and implements vm.EVMLogger.
|
||||
func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
|
||||
func newCallTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
|
||||
t, err := newCallTracerObject(ctx, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -145,10 +146,8 @@ func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer,
|
|||
|
||||
func newCallTracerObject(ctx *tracers.Context, cfg json.RawMessage) (*callTracer, error) {
|
||||
var config callTracerConfig
|
||||
if cfg != nil {
|
||||
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// First callframe contains tx context info
|
||||
// and is populated on start and end.
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type flatCallAction -field-override flatCallActionMarshaling -out gen_flatcallaction_json.go
|
||||
|
|
@ -114,6 +115,7 @@ type flatCallResultMarshaling struct {
|
|||
type flatCallTracer struct {
|
||||
tracer *callTracer
|
||||
config flatCallTracerConfig
|
||||
chainConfig *params.ChainConfig
|
||||
ctx *tracers.Context // Holds tracer context data
|
||||
interrupt atomic.Bool // Atomic flag to signal execution interruption
|
||||
activePrecompiles []common.Address // Updated on tx start based on given rules
|
||||
|
|
@ -125,22 +127,20 @@ type flatCallTracerConfig struct {
|
|||
}
|
||||
|
||||
// newFlatCallTracer returns a new flatCallTracer.
|
||||
func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
|
||||
func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
|
||||
var config flatCallTracerConfig
|
||||
if cfg != nil {
|
||||
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create inner call tracer with default configuration, don't forward
|
||||
// the OnlyTopCall or WithLog to inner for now
|
||||
t, err := newCallTracerObject(ctx, nil)
|
||||
t, err := newCallTracerObject(ctx, json.RawMessage("{}"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ft := &flatCallTracer{tracer: t, ctx: ctx, config: config}
|
||||
ft := &flatCallTracer{tracer: t, ctx: ctx, config: config, chainConfig: chainConfig}
|
||||
return &tracers.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
OnTxStart: ft.OnTxStart,
|
||||
|
|
@ -206,7 +206,7 @@ func (t *flatCallTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction
|
|||
}
|
||||
t.tracer.OnTxStart(env, tx, from)
|
||||
// Update list of precompiles based on current block
|
||||
rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time)
|
||||
rules := t.chainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time)
|
||||
t.activePrecompiles = vm.ActivePrecompiles(rules)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import (
|
|||
)
|
||||
|
||||
func TestCallFlatStop(t *testing.T) {
|
||||
tracer, err := tracers.DefaultDirectory.New("flatCallTracer", &tracers.Context{}, nil)
|
||||
tracer, err := tracers.DefaultDirectory.New("flatCallTracer", &tracers.Context{}, nil, params.MainnetChainConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
// this error should be returned by GetResult
|
||||
|
|
@ -47,9 +47,7 @@ func TestCallFlatStop(t *testing.T) {
|
|||
Data: nil,
|
||||
})
|
||||
|
||||
tracer.OnTxStart(&tracing.VMContext{
|
||||
ChainConfig: params.MainnetChainConfig,
|
||||
}, tx, common.Address{})
|
||||
tracer.OnTxStart(&tracing.VMContext{}, tx, common.Address{})
|
||||
|
||||
tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, nil, 0, big.NewInt(0))
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
@ -38,17 +39,15 @@ type muxTracer struct {
|
|||
}
|
||||
|
||||
// newMuxTracer returns a new mux tracer.
|
||||
func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
|
||||
func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
|
||||
var config map[string]json.RawMessage
|
||||
if cfg != nil {
|
||||
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
objects := make([]*tracers.Tracer, 0, len(config))
|
||||
names := make([]string, 0, len(config))
|
||||
for k, v := range config {
|
||||
t, err := tracers.DefaultDirectory.New(k, ctx, v)
|
||||
t, err := tracers.DefaultDirectory.New(k, ctx, v, chainConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
@ -35,7 +36,7 @@ func init() {
|
|||
type noopTracer struct{}
|
||||
|
||||
// newNoopTracer returns a new noop tracer.
|
||||
func newNoopTracer(ctx *tracers.Context, _ json.RawMessage) (*tracers.Tracer, error) {
|
||||
func newNoopTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
|
||||
t := &noopTracer{}
|
||||
return &tracers.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers/internal"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go
|
||||
|
|
@ -74,12 +75,10 @@ type prestateTracerConfig struct {
|
|||
DiffMode bool `json:"diffMode"` // If true, this tracer will return state modifications
|
||||
}
|
||||
|
||||
func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
|
||||
func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
|
||||
var config prestateTracerConfig
|
||||
if cfg != nil {
|
||||
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t := &prestateTracer{
|
||||
pre: stateMap{},
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ func (l panicLogger) Fatalf(format string, args ...interface{}) {
|
|||
|
||||
// New returns a wrapped pebble DB object. The namespace is the prefix that the
|
||||
// metrics reporting should use for surfacing internal stats.
|
||||
func New(file string, cache int, handles int, namespace string, readonly bool, ephemeral bool) (*Database, error) {
|
||||
func New(file string, cache int, handles int, namespace string, readonly bool) (*Database, error) {
|
||||
// Ensure we have some minimal caching and file guarantees
|
||||
if cache < minCache {
|
||||
cache = minCache
|
||||
|
|
@ -185,7 +185,7 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e
|
|||
fn: file,
|
||||
log: logger,
|
||||
quitChan: make(chan chan error),
|
||||
writeOptions: &pebble.WriteOptions{Sync: !ephemeral},
|
||||
writeOptions: &pebble.WriteOptions{Sync: false},
|
||||
}
|
||||
opt := &pebble.Options{
|
||||
// Pebble has a single combined cache area and the write
|
||||
|
|
@ -213,12 +213,12 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e
|
|||
// options for the last level are used for all subsequent levels.
|
||||
Levels: []pebble.LevelOptions{
|
||||
{TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
{TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
{TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
{TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
{TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
{TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
{TargetFileSize: 2 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
{TargetFileSize: 4 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
{TargetFileSize: 8 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
{TargetFileSize: 16 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
{TargetFileSize: 32 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
{TargetFileSize: 64 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
{TargetFileSize: 128 * 1024 * 1024, FilterPolicy: bloom.FilterPolicy(10)},
|
||||
},
|
||||
ReadOnly: readonly,
|
||||
EventListener: &pebble.EventListener{
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ func (s *Service) loop(chainHeadCh chan core.ChainHeadEvent, txEventCh chan core
|
|||
// Start a goroutine that exhausts the subscriptions to avoid events piling up
|
||||
var (
|
||||
quitCh = make(chan struct{})
|
||||
headCh = make(chan *types.Block, 1)
|
||||
headCh = make(chan *types.Header, 1)
|
||||
txCh = make(chan struct{}, 1)
|
||||
)
|
||||
go func() {
|
||||
|
|
@ -231,7 +231,7 @@ func (s *Service) loop(chainHeadCh chan core.ChainHeadEvent, txEventCh chan core
|
|||
// Notify of chain head events, but drop if too frequent
|
||||
case head := <-chainHeadCh:
|
||||
select {
|
||||
case headCh <- head.Block:
|
||||
case headCh <- head.Header:
|
||||
default:
|
||||
}
|
||||
|
||||
|
|
@ -602,9 +602,9 @@ func (s uncleStats) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
|
||||
// reportBlock retrieves the current chain head and reports it to the stats server.
|
||||
func (s *Service) reportBlock(conn *connWrapper, block *types.Block) error {
|
||||
func (s *Service) reportBlock(conn *connWrapper, header *types.Header) error {
|
||||
// Gather the block details from the header or block chain
|
||||
details := s.assembleBlockStats(block)
|
||||
details := s.assembleBlockStats(header)
|
||||
|
||||
// Short circuit if the block detail is not available.
|
||||
if details == nil {
|
||||
|
|
@ -625,10 +625,9 @@ func (s *Service) reportBlock(conn *connWrapper, block *types.Block) error {
|
|||
|
||||
// assembleBlockStats retrieves any required metadata to report a single block
|
||||
// and assembles the block stats. If block is nil, the current head is processed.
|
||||
func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
|
||||
func (s *Service) assembleBlockStats(header *types.Header) *blockStats {
|
||||
// Gather the block infos from the local blockchain
|
||||
var (
|
||||
header *types.Header
|
||||
td *big.Int
|
||||
txs []txStats
|
||||
uncles []*types.Header
|
||||
|
|
@ -638,16 +637,13 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
|
|||
fullBackend, ok := s.backend.(fullNodeBackend)
|
||||
if ok {
|
||||
// Retrieve current chain head if no block is given.
|
||||
if block == nil {
|
||||
head := fullBackend.CurrentBlock()
|
||||
block, _ = fullBackend.BlockByNumber(context.Background(), rpc.BlockNumber(head.Number.Uint64()))
|
||||
if header == nil {
|
||||
header = fullBackend.CurrentBlock()
|
||||
}
|
||||
// Short circuit if no block is available. It might happen when
|
||||
// the blockchain is reorging.
|
||||
block, _ := fullBackend.BlockByNumber(context.Background(), rpc.BlockNumber(header.Number.Uint64()))
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
header = block.Header()
|
||||
td = fullBackend.GetTd(context.Background(), header.Hash())
|
||||
|
||||
txs = make([]txStats, len(block.Transactions()))
|
||||
|
|
@ -657,15 +653,12 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
|
|||
uncles = block.Uncles()
|
||||
} else {
|
||||
// Light nodes would need on-demand lookups for transactions/uncles, skip
|
||||
if block != nil {
|
||||
header = block.Header()
|
||||
} else {
|
||||
if header == nil {
|
||||
header = s.backend.CurrentHeader()
|
||||
}
|
||||
td = s.backend.GetTd(context.Background(), header.Hash())
|
||||
txs = []txStats{}
|
||||
}
|
||||
|
||||
// Assemble and return the block stats
|
||||
author, _ := s.engine.Author(header)
|
||||
|
||||
|
|
@ -708,19 +701,10 @@ func (s *Service) reportHistory(conn *connWrapper, list []uint64) error {
|
|||
// Gather the batch of blocks to report
|
||||
history := make([]*blockStats, len(indexes))
|
||||
for i, number := range indexes {
|
||||
fullBackend, ok := s.backend.(fullNodeBackend)
|
||||
// Retrieve the next block if it's known to us
|
||||
var block *types.Block
|
||||
if ok {
|
||||
block, _ = fullBackend.BlockByNumber(context.Background(), rpc.BlockNumber(number)) // TODO ignore error here ?
|
||||
} else {
|
||||
if header, _ := s.backend.HeaderByNumber(context.Background(), rpc.BlockNumber(number)); header != nil {
|
||||
block = types.NewBlockWithHeader(header)
|
||||
}
|
||||
}
|
||||
// If we do have the block, add to the history and continue
|
||||
if block != nil {
|
||||
history[len(history)-1-i] = s.assembleBlockStats(block)
|
||||
header, _ := s.backend.HeaderByNumber(context.Background(), rpc.BlockNumber(number))
|
||||
if header != nil {
|
||||
history[len(history)-1-i] = s.assembleBlockStats(header)
|
||||
continue
|
||||
}
|
||||
// Ran out of blocks, cut the report short and send
|
||||
|
|
|
|||
3
go.mod
3
go.mod
|
|
@ -12,7 +12,6 @@ require (
|
|||
github.com/aws/aws-sdk-go-v2/config v1.18.45
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.43
|
||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4
|
||||
github.com/cespare/cp v0.1.0
|
||||
github.com/cloudflare/cloudflare-go v0.79.0
|
||||
github.com/cockroachdb/pebble v1.1.2
|
||||
|
|
@ -21,6 +20,7 @@ require (
|
|||
github.com/crate-crypto/go-kzg-4844 v1.0.0
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/deckarep/golang-set/v2 v2.6.0
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1
|
||||
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0
|
||||
github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3
|
||||
github.com/ethereum/c-kzg-4844 v1.0.0
|
||||
|
|
@ -109,7 +109,6 @@ require (
|
|||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
|
||||
github.com/consensys/bavard v0.1.13 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||
github.com/deepmap/oapi-codegen v1.6.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.7.0 // indirect
|
||||
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -92,10 +92,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
|||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
|
||||
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
||||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||
|
|
|
|||
|
|
@ -587,9 +587,6 @@ func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscr
|
|||
func (b testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
|
||||
panic("implement me")
|
||||
}
|
||||
func (b testBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
|
||||
panic("implement me")
|
||||
}
|
||||
func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ type Backend interface {
|
|||
GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM
|
||||
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
|
||||
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
|
||||
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
|
||||
|
||||
// Transaction pool API
|
||||
SendTx(ctx context.Context, signedTx *types.Transaction) error
|
||||
|
|
|
|||
|
|
@ -189,9 +189,7 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) erro
|
|||
if args.BlobFeeCap != nil && args.BlobFeeCap.ToInt().Sign() == 0 {
|
||||
return errors.New("maxFeePerBlobGas, if specified, must be non-zero")
|
||||
}
|
||||
if err := args.setCancunFeeDefaults(ctx, head, b); err != nil {
|
||||
return err
|
||||
}
|
||||
args.setCancunFeeDefaults(head)
|
||||
// If both gasPrice and at least one of the EIP-1559 fee parameters are specified, error.
|
||||
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
|
||||
return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
||||
|
|
@ -243,7 +241,7 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) erro
|
|||
}
|
||||
|
||||
// setCancunFeeDefaults fills in reasonable default fee values for unspecified fields.
|
||||
func (args *TransactionArgs) setCancunFeeDefaults(ctx context.Context, head *types.Header, b Backend) error {
|
||||
func (args *TransactionArgs) setCancunFeeDefaults(head *types.Header) {
|
||||
// Set maxFeePerBlobGas if it is missing.
|
||||
if args.BlobHashes != nil && args.BlobFeeCap == nil {
|
||||
var excessBlobGas uint64
|
||||
|
|
@ -258,7 +256,6 @@ func (args *TransactionArgs) setCancunFeeDefaults(ctx context.Context, head *typ
|
|||
val := new(big.Int).Mul(blobBaseFee, big.NewInt(2))
|
||||
args.BlobFeeCap = (*hexutil.Big)(val)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setLondonFeeDefaults fills in reasonable default fee values for unspecified fields.
|
||||
|
|
|
|||
|
|
@ -377,9 +377,6 @@ func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subsc
|
|||
func (b *backendMock) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
|
||||
return nil
|
||||
}
|
||||
func (b *backendMock) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
|
||||
return nil
|
||||
}
|
||||
func (b *backendMock) SendTx(ctx context.Context, signedTx *types.Transaction) error { return nil }
|
||||
func (b *backendMock) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) {
|
||||
return false, nil, [32]byte{}, 0, 0, nil
|
||||
|
|
|
|||
|
|
@ -17,15 +17,12 @@
|
|||
package flags
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPathExpansion(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
user, _ := user.Current()
|
||||
var tests map[string]string
|
||||
|
||||
|
|
@ -53,7 +50,7 @@ func TestPathExpansion(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
os.Setenv(`DDDXXX`, `/tmp`)
|
||||
t.Setenv(`DDDXXX`, `/tmp`)
|
||||
for test, expected := range tests {
|
||||
t.Run(test, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ func TestRegistryMarshallJSON(t *testing.T) {
|
|||
r.Register("counter", NewCounter())
|
||||
enc.Encode(r)
|
||||
if s := b.String(); s != "{\"counter\":{\"count\":0}}\n" {
|
||||
t.Fatalf(s)
|
||||
t.Fatal(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,26 +69,28 @@ func (args *BuildPayloadArgs) Id() engine.PayloadID {
|
|||
// the revenue. Therefore, the empty-block here is always available and full-block
|
||||
// will be set/updated afterwards.
|
||||
type Payload struct {
|
||||
id engine.PayloadID
|
||||
empty *types.Block
|
||||
emptyWitness *stateless.Witness
|
||||
full *types.Block
|
||||
fullWitness *stateless.Witness
|
||||
sidecars []*types.BlobTxSidecar
|
||||
requests [][]byte
|
||||
fullFees *big.Int
|
||||
stop chan struct{}
|
||||
lock sync.Mutex
|
||||
cond *sync.Cond
|
||||
id engine.PayloadID
|
||||
empty *types.Block
|
||||
emptyWitness *stateless.Witness
|
||||
full *types.Block
|
||||
fullWitness *stateless.Witness
|
||||
sidecars []*types.BlobTxSidecar
|
||||
emptyRequests [][]byte
|
||||
requests [][]byte
|
||||
fullFees *big.Int
|
||||
stop chan struct{}
|
||||
lock sync.Mutex
|
||||
cond *sync.Cond
|
||||
}
|
||||
|
||||
// newPayload initializes the payload object.
|
||||
func newPayload(empty *types.Block, witness *stateless.Witness, id engine.PayloadID) *Payload {
|
||||
func newPayload(empty *types.Block, emptyRequests [][]byte, witness *stateless.Witness, id engine.PayloadID) *Payload {
|
||||
payload := &Payload{
|
||||
id: id,
|
||||
empty: empty,
|
||||
emptyWitness: witness,
|
||||
stop: make(chan struct{}),
|
||||
id: id,
|
||||
empty: empty,
|
||||
emptyRequests: emptyRequests,
|
||||
emptyWitness: witness,
|
||||
stop: make(chan struct{}),
|
||||
}
|
||||
log.Info("Starting work on payload", "id", payload.id)
|
||||
payload.cond = sync.NewCond(&payload.lock)
|
||||
|
|
@ -143,16 +145,14 @@ func (payload *Payload) Resolve() *engine.ExecutionPayloadEnvelope {
|
|||
close(payload.stop)
|
||||
}
|
||||
if payload.full != nil {
|
||||
envelope := engine.BlockToExecutableData(payload.full, payload.fullFees, payload.sidecars)
|
||||
envelope.Requests = payload.requests
|
||||
envelope := engine.BlockToExecutableData(payload.full, payload.fullFees, payload.sidecars, payload.emptyRequests)
|
||||
if payload.fullWitness != nil {
|
||||
envelope.Witness = new(hexutil.Bytes)
|
||||
*envelope.Witness, _ = rlp.EncodeToBytes(payload.fullWitness) // cannot fail
|
||||
}
|
||||
return envelope
|
||||
}
|
||||
envelope := engine.BlockToExecutableData(payload.empty, big.NewInt(0), nil)
|
||||
envelope.Requests = payload.requests
|
||||
envelope := engine.BlockToExecutableData(payload.empty, big.NewInt(0), nil, payload.emptyRequests)
|
||||
if payload.emptyWitness != nil {
|
||||
envelope.Witness = new(hexutil.Bytes)
|
||||
*envelope.Witness, _ = rlp.EncodeToBytes(payload.emptyWitness) // cannot fail
|
||||
|
|
@ -166,8 +166,7 @@ func (payload *Payload) ResolveEmpty() *engine.ExecutionPayloadEnvelope {
|
|||
payload.lock.Lock()
|
||||
defer payload.lock.Unlock()
|
||||
|
||||
envelope := engine.BlockToExecutableData(payload.empty, big.NewInt(0), nil)
|
||||
envelope.Requests = payload.requests
|
||||
envelope := engine.BlockToExecutableData(payload.empty, big.NewInt(0), nil, payload.emptyRequests)
|
||||
if payload.emptyWitness != nil {
|
||||
envelope.Witness = new(hexutil.Bytes)
|
||||
*envelope.Witness, _ = rlp.EncodeToBytes(payload.emptyWitness) // cannot fail
|
||||
|
|
@ -198,8 +197,7 @@ func (payload *Payload) ResolveFull() *engine.ExecutionPayloadEnvelope {
|
|||
default:
|
||||
close(payload.stop)
|
||||
}
|
||||
envelope := engine.BlockToExecutableData(payload.full, payload.fullFees, payload.sidecars)
|
||||
envelope.Requests = payload.requests
|
||||
envelope := engine.BlockToExecutableData(payload.full, payload.fullFees, payload.sidecars, payload.requests)
|
||||
if payload.fullWitness != nil {
|
||||
envelope.Witness = new(hexutil.Bytes)
|
||||
*envelope.Witness, _ = rlp.EncodeToBytes(payload.fullWitness) // cannot fail
|
||||
|
|
@ -227,7 +225,7 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs, witness bool) (*Payload
|
|||
return nil, empty.err
|
||||
}
|
||||
// Construct a payload object for return.
|
||||
payload := newPayload(empty.block, empty.witness, args.Id())
|
||||
payload := newPayload(empty.block, empty.requests, empty.witness, args.Id())
|
||||
|
||||
// Spin up a routine for updating the payload in background. This strategy
|
||||
// can maximum the revenue for including transactions with highest fee.
|
||||
|
|
|
|||
|
|
@ -244,7 +244,6 @@ func TestStartRPC(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
|||
|
|
@ -513,7 +513,6 @@ func TestNodeRPCPrefix(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
name := fmt.Sprintf("http=%s ws=%s", test.httpPrefix, test.wsPrefix)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
cfg := &Config{
|
||||
|
|
|
|||
|
|
@ -522,7 +522,6 @@ func TestGzipHandler(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
srv := httptest.NewServer(newGzipHandler(test.handler))
|
||||
defer srv.Close()
|
||||
|
|
|
|||
|
|
@ -395,7 +395,6 @@ func TestTestVectorsV5(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
net := newHandshakeTest()
|
||||
defer net.close()
|
||||
|
|
|
|||
|
|
@ -412,7 +412,6 @@ outer:
|
|||
func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error) {
|
||||
p.wg.Add(len(p.running))
|
||||
for _, proto := range p.running {
|
||||
proto := proto
|
||||
proto.closed = p.closed
|
||||
proto.wstart = writeStart
|
||||
proto.werr = writeErr
|
||||
|
|
|
|||
|
|
@ -307,7 +307,6 @@ func TestStreamReadBytes(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
name := fmt.Sprintf("input_%s/size_%d", test.input, test.size)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
s := NewStream(bytes.NewReader(unhex(test.input)), 0)
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ var tests = []string{"uints", "nil", "rawvalue", "optional", "bigint", "uint256"
|
|||
|
||||
func TestOutput(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test, func(t *testing.T) {
|
||||
inputFile := filepath.Join("testdata", test+".in.txt")
|
||||
outputFile := filepath.Join("testdata", test+".out.txt")
|
||||
|
|
|
|||
|
|
@ -776,7 +776,6 @@ func TestClientHTTP(t *testing.T) {
|
|||
wantResult = echoResult{"a", 1, new(echoArgs)}
|
||||
)
|
||||
for i := range results {
|
||||
i := i
|
||||
go func() {
|
||||
errc <- client.Call(&results[i], "test_echo", wantResult.String, wantResult.Int, wantResult.Args)
|
||||
}()
|
||||
|
|
|
|||
|
|
@ -143,7 +143,6 @@ func TestBlockNumberOrHash_WithNumber_MarshalAndUnmarshal(t *testing.T) {
|
|||
{"finalized", int64(FinalizedBlockNumber)},
|
||||
}
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
bnh := BlockNumberOrHashWithNumber(BlockNumber(test.number))
|
||||
marshalled, err := json.Marshal(bnh)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
dcred_secp256k1 "github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||
)
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ func Fuzz(f *testing.F) {
|
|||
func fuzz(dataP1, dataP2 []byte) {
|
||||
var (
|
||||
curveA = secp256k1.S256()
|
||||
curveB = btcec.S256()
|
||||
curveB = dcred_secp256k1.S256()
|
||||
)
|
||||
// first point
|
||||
x1, y1 := curveB.ScalarBaseMult(dataP1)
|
||||
|
|
|
|||
|
|
@ -104,7 +104,6 @@ func TestExecutionSpecState(t *testing.T) {
|
|||
|
||||
func execStateTest(t *testing.T, st *testMatcher, test *StateTest) {
|
||||
for _, subtest := range test.Subtests() {
|
||||
subtest := subtest
|
||||
key := fmt.Sprintf("%s/%d", subtest.Fork, subtest.Index)
|
||||
|
||||
// If -short flag is used, we don't execute all four permutations, only
|
||||
|
|
@ -244,14 +243,12 @@ func runBenchmarkFile(b *testing.B, path string) {
|
|||
return
|
||||
}
|
||||
for _, t := range m {
|
||||
t := t
|
||||
runBenchmark(b, &t)
|
||||
}
|
||||
}
|
||||
|
||||
func runBenchmark(b *testing.B, t *StateTest) {
|
||||
for _, subtest := range t.Subtests() {
|
||||
subtest := subtest
|
||||
key := fmt.Sprintf("%s/%d", subtest.Fork, subtest.Index)
|
||||
|
||||
b.Run(key, func(b *testing.B) {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package trie
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||
|
|
@ -42,12 +43,12 @@ func newCommitter(nodeset *trienode.NodeSet, tracer *tracer, collectLeaf bool) *
|
|||
}
|
||||
|
||||
// Commit collapses a node down into a hash node.
|
||||
func (c *committer) Commit(n node) hashNode {
|
||||
return c.commit(nil, n).(hashNode)
|
||||
func (c *committer) Commit(n node, parallel bool) hashNode {
|
||||
return c.commit(nil, n, parallel).(hashNode)
|
||||
}
|
||||
|
||||
// commit collapses a node down into a hash node and returns it.
|
||||
func (c *committer) commit(path []byte, n node) node {
|
||||
func (c *committer) commit(path []byte, n node, parallel bool) node {
|
||||
// if this path is clean, use available cached data
|
||||
hash, dirty := n.cache()
|
||||
if hash != nil && !dirty {
|
||||
|
|
@ -62,7 +63,7 @@ func (c *committer) commit(path []byte, n node) node {
|
|||
// If the child is fullNode, recursively commit,
|
||||
// otherwise it can only be hashNode or valueNode.
|
||||
if _, ok := cn.Val.(*fullNode); ok {
|
||||
collapsed.Val = c.commit(append(path, cn.Key...), cn.Val)
|
||||
collapsed.Val = c.commit(append(path, cn.Key...), cn.Val, false)
|
||||
}
|
||||
// The key needs to be copied, since we're adding it to the
|
||||
// modified nodeset.
|
||||
|
|
@ -73,7 +74,7 @@ func (c *committer) commit(path []byte, n node) node {
|
|||
}
|
||||
return collapsed
|
||||
case *fullNode:
|
||||
hashedKids := c.commitChildren(path, cn)
|
||||
hashedKids := c.commitChildren(path, cn, parallel)
|
||||
collapsed := cn.copy()
|
||||
collapsed.Children = hashedKids
|
||||
|
||||
|
|
@ -91,8 +92,12 @@ func (c *committer) commit(path []byte, n node) node {
|
|||
}
|
||||
|
||||
// commitChildren commits the children of the given fullnode
|
||||
func (c *committer) commitChildren(path []byte, n *fullNode) [17]node {
|
||||
var children [17]node
|
||||
func (c *committer) commitChildren(path []byte, n *fullNode, parallel bool) [17]node {
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
nodesMu sync.Mutex
|
||||
children [17]node
|
||||
)
|
||||
for i := 0; i < 16; i++ {
|
||||
child := n.Children[i]
|
||||
if child == nil {
|
||||
|
|
@ -108,7 +113,24 @@ func (c *committer) commitChildren(path []byte, n *fullNode) [17]node {
|
|||
// Commit the child recursively and store the "hashed" value.
|
||||
// Note the returned node can be some embedded nodes, so it's
|
||||
// possible the type is not hashNode.
|
||||
children[i] = c.commit(append(path, byte(i)), child)
|
||||
if !parallel {
|
||||
children[i] = c.commit(append(path, byte(i)), child, false)
|
||||
} else {
|
||||
wg.Add(1)
|
||||
go func(index int) {
|
||||
p := append(path, byte(index))
|
||||
childSet := trienode.NewNodeSet(c.nodes.Owner)
|
||||
childCommitter := newCommitter(childSet, c.tracer, c.collectLeaf)
|
||||
children[index] = childCommitter.commit(p, child, false)
|
||||
nodesMu.Lock()
|
||||
c.nodes.MergeSet(childSet)
|
||||
nodesMu.Unlock()
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
}
|
||||
if parallel {
|
||||
wg.Wait()
|
||||
}
|
||||
// For the 17th child, it's possible the type is valuenode.
|
||||
if n.Children[16] != nil {
|
||||
|
|
|
|||
23
trie/trie.go
23
trie/trie.go
|
|
@ -49,6 +49,9 @@ type Trie struct {
|
|||
// actually unhashed nodes.
|
||||
unhashed int
|
||||
|
||||
// uncommitted is the number of updates since last commit.
|
||||
uncommitted int
|
||||
|
||||
// reader is the handler trie can retrieve nodes from.
|
||||
reader *trieReader
|
||||
|
||||
|
|
@ -64,12 +67,13 @@ func (t *Trie) newFlag() nodeFlag {
|
|||
// Copy returns a copy of Trie.
|
||||
func (t *Trie) Copy() *Trie {
|
||||
return &Trie{
|
||||
root: t.root,
|
||||
owner: t.owner,
|
||||
committed: t.committed,
|
||||
unhashed: t.unhashed,
|
||||
reader: t.reader,
|
||||
tracer: t.tracer.copy(),
|
||||
root: t.root,
|
||||
owner: t.owner,
|
||||
committed: t.committed,
|
||||
reader: t.reader,
|
||||
tracer: t.tracer.copy(),
|
||||
uncommitted: t.uncommitted,
|
||||
unhashed: t.unhashed,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -309,6 +313,7 @@ func (t *Trie) Update(key, value []byte) error {
|
|||
|
||||
func (t *Trie) update(key, value []byte) error {
|
||||
t.unhashed++
|
||||
t.uncommitted++
|
||||
k := keybytesToHex(key)
|
||||
if len(value) != 0 {
|
||||
_, n, err := t.insert(t.root, nil, k, valueNode(value))
|
||||
|
|
@ -422,6 +427,7 @@ func (t *Trie) Delete(key []byte) error {
|
|||
if t.committed {
|
||||
return ErrCommitted
|
||||
}
|
||||
t.uncommitted++
|
||||
t.unhashed++
|
||||
k := keybytesToHex(key)
|
||||
_, n, err := t.delete(t.root, nil, k)
|
||||
|
|
@ -642,7 +648,9 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) {
|
|||
for _, path := range t.tracer.deletedNodes() {
|
||||
nodes.AddNode([]byte(path), trienode.NewDeleted())
|
||||
}
|
||||
t.root = newCommitter(nodes, t.tracer, collectLeaf).Commit(t.root)
|
||||
// If the number of changes is below 100, we let one thread handle it
|
||||
t.root = newCommitter(nodes, t.tracer, collectLeaf).Commit(t.root, t.uncommitted > 100)
|
||||
t.uncommitted = 0
|
||||
return rootHash, nodes
|
||||
}
|
||||
|
||||
|
|
@ -678,6 +686,7 @@ func (t *Trie) Reset() {
|
|||
t.root = nil
|
||||
t.owner = common.Hash{}
|
||||
t.unhashed = 0
|
||||
t.uncommitted = 0
|
||||
t.tracer.reset()
|
||||
t.committed = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
"math/rand"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
|
||||
|
|
@ -35,6 +36,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/internal/testrand"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||
"github.com/holiman/uint256"
|
||||
|
|
@ -1206,3 +1208,105 @@ func FuzzTrie(f *testing.F) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkCommit(b *testing.B) {
|
||||
benchmarkCommit(b, 100)
|
||||
benchmarkCommit(b, 500)
|
||||
benchmarkCommit(b, 2000)
|
||||
benchmarkCommit(b, 5000)
|
||||
}
|
||||
|
||||
func benchmarkCommit(b *testing.B, n int) {
|
||||
b.Run(fmt.Sprintf("commit-%vnodes-sequential", n), func(b *testing.B) {
|
||||
testCommit(b, n, false)
|
||||
})
|
||||
b.Run(fmt.Sprintf("commit-%vnodes-parallel", n), func(b *testing.B) {
|
||||
testCommit(b, n, true)
|
||||
})
|
||||
}
|
||||
|
||||
func testCommit(b *testing.B, n int, parallel bool) {
|
||||
tries := make([]*Trie, b.N)
|
||||
for i := 0; i < b.N; i++ {
|
||||
tries[i] = NewEmpty(nil)
|
||||
for j := 0; j < n; j++ {
|
||||
key := testrand.Bytes(32)
|
||||
val := testrand.Bytes(32)
|
||||
tries[i].Update(key, val)
|
||||
}
|
||||
tries[i].Hash()
|
||||
if !parallel {
|
||||
tries[i].uncommitted = 0
|
||||
}
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < len(tries); i++ {
|
||||
tries[i].Commit(true)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitCorrect(t *testing.T) {
|
||||
var paraTrie = NewEmpty(nil)
|
||||
var refTrie = NewEmpty(nil)
|
||||
|
||||
for j := 0; j < 5000; j++ {
|
||||
key := testrand.Bytes(32)
|
||||
val := testrand.Bytes(32)
|
||||
paraTrie.Update(key, val)
|
||||
refTrie.Update(common.CopyBytes(key), common.CopyBytes(val))
|
||||
}
|
||||
paraTrie.Hash()
|
||||
refTrie.Hash()
|
||||
refTrie.uncommitted = 0
|
||||
|
||||
haveRoot, haveNodes := paraTrie.Commit(true)
|
||||
wantRoot, wantNodes := refTrie.Commit(true)
|
||||
|
||||
if haveRoot != wantRoot {
|
||||
t.Fatalf("have %x want %x", haveRoot, wantRoot)
|
||||
}
|
||||
have := printSet(haveNodes)
|
||||
want := printSet(wantNodes)
|
||||
if have != want {
|
||||
i := 0
|
||||
for i = 0; i < len(have); i++ {
|
||||
if have[i] != want[i] {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i > 100 {
|
||||
i -= 100
|
||||
}
|
||||
t.Fatalf("have != want\nhave %q\nwant %q", have[i:], want[i:])
|
||||
}
|
||||
}
|
||||
func printSet(set *trienode.NodeSet) string {
|
||||
var out = new(strings.Builder)
|
||||
fmt.Fprintf(out, "nodeset owner: %v\n", set.Owner)
|
||||
var paths []string
|
||||
for k := range set.Nodes {
|
||||
paths = append(paths, k)
|
||||
}
|
||||
sort.Strings(paths)
|
||||
|
||||
for _, path := range paths {
|
||||
n := set.Nodes[path]
|
||||
// Deletion
|
||||
if n.IsDeleted() {
|
||||
fmt.Fprintf(out, " [-]: %x\n", path)
|
||||
continue
|
||||
}
|
||||
// Insertion or update
|
||||
fmt.Fprintf(out, " [+/*]: %x -> %v \n", path, n.Hash)
|
||||
}
|
||||
sort.Slice(set.Leaves, func(i, j int) bool {
|
||||
a := set.Leaves[i]
|
||||
b := set.Leaves[j]
|
||||
return bytes.Compare(a.Parent[:], b.Parent[:]) < 0
|
||||
})
|
||||
for _, n := range set.Leaves {
|
||||
fmt.Fprintf(out, "[leaf]: %v\n", n)
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue