mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 06:06:44 +00:00
Merge tag 'v1.11.4' into merge_v1.11.4
This commit is contained in:
commit
ba8aaf38b9
54 changed files with 1330 additions and 741 deletions
48
.travis.yml
48
.travis.yml
|
|
@ -57,30 +57,6 @@ jobs:
|
||||||
script:
|
script:
|
||||||
- go run build/ci.go docker -image -manifest amd64,arm64 -upload ethereum/client-go
|
- go run build/ci.go docker -image -manifest amd64,arm64 -upload ethereum/client-go
|
||||||
|
|
||||||
# This builder does the Ubuntu PPA upload
|
|
||||||
- stage: build
|
|
||||||
if: type = push
|
|
||||||
os: linux
|
|
||||||
dist: bionic
|
|
||||||
go: 1.20.x
|
|
||||||
env:
|
|
||||||
- ubuntu-ppa
|
|
||||||
- GO111MODULE=on
|
|
||||||
git:
|
|
||||||
submodules: false # avoid cloning ethereum/tests
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- devscripts
|
|
||||||
- debhelper
|
|
||||||
- dput
|
|
||||||
- fakeroot
|
|
||||||
- python-bzrlib
|
|
||||||
- python-paramiko
|
|
||||||
script:
|
|
||||||
- echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts
|
|
||||||
- go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>"
|
|
||||||
|
|
||||||
# This builder does the Linux Azure uploads
|
# This builder does the Linux Azure uploads
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = push
|
if: type = push
|
||||||
|
|
@ -162,6 +138,30 @@ jobs:
|
||||||
script:
|
script:
|
||||||
- go run build/ci.go test $TEST_PACKAGES
|
- go run build/ci.go test $TEST_PACKAGES
|
||||||
|
|
||||||
|
# This builder does the Ubuntu PPA nightly uploads
|
||||||
|
- stage: build
|
||||||
|
if: type = cron
|
||||||
|
os: linux
|
||||||
|
dist: bionic
|
||||||
|
go: 1.20.x
|
||||||
|
env:
|
||||||
|
- ubuntu-ppa
|
||||||
|
- GO111MODULE=on
|
||||||
|
git:
|
||||||
|
submodules: false # avoid cloning ethereum/tests
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- devscripts
|
||||||
|
- debhelper
|
||||||
|
- dput
|
||||||
|
- fakeroot
|
||||||
|
- python-bzrlib
|
||||||
|
- python-paramiko
|
||||||
|
script:
|
||||||
|
- echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts
|
||||||
|
- go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>"
|
||||||
|
|
||||||
# This builder does the Azure archive purges to avoid accumulating junk
|
# This builder does the Azure archive purges to avoid accumulating junk
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = cron
|
if: type = cron
|
||||||
|
|
|
||||||
|
|
@ -644,20 +644,33 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
||||||
if call.Value == nil {
|
if call.Value == nil {
|
||||||
call.Value = new(big.Int)
|
call.Value = new(big.Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set infinite balance to the fake caller account.
|
// Set infinite balance to the fake caller account.
|
||||||
from := stateDB.GetOrNewStateObject(call.From)
|
from := stateDB.GetOrNewStateObject(call.From)
|
||||||
from.SetBalance(math.MaxBig256)
|
from.SetBalance(math.MaxBig256)
|
||||||
// Execute the call.
|
|
||||||
msg := callMsg{call}
|
|
||||||
|
|
||||||
txContext := core.NewEVMTxContext(msg)
|
// Execute the call.
|
||||||
evmContext := core.NewEVMBlockContext(header, b.blockchain, nil)
|
msg := &core.Message{
|
||||||
|
From: call.From,
|
||||||
|
To: call.To,
|
||||||
|
Value: call.Value,
|
||||||
|
GasLimit: call.Gas,
|
||||||
|
GasPrice: call.GasPrice,
|
||||||
|
GasFeeCap: call.GasFeeCap,
|
||||||
|
GasTipCap: call.GasTipCap,
|
||||||
|
Data: call.Data,
|
||||||
|
AccessList: call.AccessList,
|
||||||
|
SkipAccountChecks: true,
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new environment which holds all relevant information
|
// Create a new environment which holds all relevant information
|
||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
|
txContext := core.NewEVMTxContext(msg)
|
||||||
|
evmContext := core.NewEVMBlockContext(header, b.blockchain, nil)
|
||||||
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
|
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
|
||||||
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
|
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
|
||||||
|
|
||||||
return core.NewStateTransition(vmEnv, msg, gasPool).TransitionDb()
|
return core.ApplyMessage(vmEnv, msg, gasPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendTransaction updates the pending block to include the given transaction.
|
// SendTransaction updates the pending block to include the given transaction.
|
||||||
|
|
@ -821,24 +834,6 @@ func (b *SimulatedBackend) Blockchain() *core.BlockChain {
|
||||||
return b.blockchain
|
return b.blockchain
|
||||||
}
|
}
|
||||||
|
|
||||||
// callMsg implements core.Message to allow passing it as a transaction simulator.
|
|
||||||
type callMsg struct {
|
|
||||||
ethereum.CallMsg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m callMsg) From() common.Address { return m.CallMsg.From }
|
|
||||||
func (m callMsg) Nonce() uint64 { return 0 }
|
|
||||||
func (m callMsg) IsFake() bool { return true }
|
|
||||||
func (m callMsg) IsPre() bool { return false }
|
|
||||||
func (m callMsg) To() *common.Address { return m.CallMsg.To }
|
|
||||||
func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
|
||||||
func (m callMsg) GasFeeCap() *big.Int { return m.CallMsg.GasFeeCap }
|
|
||||||
func (m callMsg) GasTipCap() *big.Int { return m.CallMsg.GasTipCap }
|
|
||||||
func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
|
|
||||||
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
|
|
||||||
func (m callMsg) Data() []byte { return m.CallMsg.Data }
|
|
||||||
func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList }
|
|
||||||
|
|
||||||
// filterBackend implements filters.Backend to support filtering for logs without
|
// filterBackend implements filters.Backend to support filtering for logs without
|
||||||
// taking bloom-bits acceleration structures into account.
|
// taking bloom-bits acceleration structures into account.
|
||||||
type filterBackend struct {
|
type filterBackend struct {
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
msg, err := tx.AsMessage(signer, pre.Env.BaseFee)
|
msg, err := core.TransactionToMessage(tx, signer, pre.Env.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err)
|
log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err)
|
||||||
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
||||||
|
|
@ -188,7 +188,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
|
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statedb.RevertToSnapshot(snapshot)
|
statedb.RevertToSnapshot(snapshot)
|
||||||
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err)
|
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
|
||||||
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
|
||||||
gaspool.SetGas(prevGas)
|
gaspool.SetGas(prevGas)
|
||||||
continue
|
continue
|
||||||
|
|
@ -220,7 +220,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
receipt.GasUsed = msgResult.UsedGas
|
receipt.GasUsed = msgResult.UsedGas
|
||||||
|
|
||||||
// If the transaction created a contract, store the creation address in the receipt.
|
// If the transaction created a contract, store the creation address in the receipt.
|
||||||
if msg.To() == nil {
|
if msg.To == nil {
|
||||||
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
12
cmd/evm/testdata/10/readme.md
vendored
12
cmd/evm/testdata/10/readme.md
vendored
|
|
@ -27,7 +27,7 @@ Output:
|
||||||
"result": {
|
"result": {
|
||||||
"stateRoot": "0xf91a7ec08e4bfea88719aab34deabb000c86902360532b52afa9599d41f2bb8b",
|
"stateRoot": "0xf91a7ec08e4bfea88719aab34deabb000c86902360532b52afa9599d41f2bb8b",
|
||||||
"txRoot": "0xda925f2306a52fa24c15d5cd212d736ee016415fd8dd0c45fd368de7917d64bb",
|
"txRoot": "0xda925f2306a52fa24c15d5cd212d736ee016415fd8dd0c45fd368de7917d64bb",
|
||||||
"receiptRoot": "0x439a25f7fc424c10fb1f89800e4aa1df74156b137239d9ac3eaa7c911c353cd5",
|
"receiptsRoot": "0x439a25f7fc424c10fb1f89800e4aa1df74156b137239d9ac3eaa7c911c353cd5",
|
||||||
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"receipts": [
|
"receipts": [
|
||||||
|
|
@ -72,8 +72,14 @@ Output:
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"rejected": [
|
"rejected": [
|
||||||
3
|
{
|
||||||
]
|
"index": 3,
|
||||||
|
"error": "gas limit reached"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"currentDifficulty": "0x20000",
|
||||||
|
"gasUsed": "0x30000001",
|
||||||
|
"currentBaseFee": "0x36b"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
13
cmd/evm/testdata/12/readme.md
vendored
13
cmd/evm/testdata/12/readme.md
vendored
|
|
@ -11,9 +11,9 @@ dir=./testdata/12 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json
|
||||||
With the fix applied, the result is:
|
With the fix applied, the result is:
|
||||||
```
|
```
|
||||||
dir=./testdata/12 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout --output.result=stdout
|
dir=./testdata/12 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout --output.result=stdout
|
||||||
INFO [07-21|19:03:50.276] rejected tx index=0 hash=ccc996..d83435 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="insufficient funds for gas * price + value: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B have 84000000 want 84000032"
|
INFO [03-09|10:43:12.649] rejected tx index=0 hash=ccc996..d83435 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="insufficient funds for gas * price + value: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B have 84000000 want 84000032"
|
||||||
INFO [07-21|19:03:50.276] Trie dumping started root=e05f81..6597a5
|
INFO [03-09|10:43:12.650] Trie dumping started root=e05f81..6597a5
|
||||||
INFO [07-21|19:03:50.276] Trie dumping complete accounts=1 elapsed="39.549µs"
|
INFO [03-09|10:43:12.650] Trie dumping complete accounts=1 elapsed="46.393µs"
|
||||||
{
|
{
|
||||||
"alloc": {
|
"alloc": {
|
||||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||||
|
|
@ -23,7 +23,7 @@ INFO [07-21|19:03:50.276] Trie dumping complete accounts=1 el
|
||||||
"result": {
|
"result": {
|
||||||
"stateRoot": "0xe05f81f8244a76503ceec6f88abfcd03047a612a1001217f37d30984536597a5",
|
"stateRoot": "0xe05f81f8244a76503ceec6f88abfcd03047a612a1001217f37d30984536597a5",
|
||||||
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||||
"receiptRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||||
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"receipts": [],
|
"receipts": [],
|
||||||
|
|
@ -32,7 +32,10 @@ INFO [07-21|19:03:50.276] Trie dumping complete accounts=1 el
|
||||||
"index": 0,
|
"index": 0,
|
||||||
"error": "insufficient funds for gas * price + value: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B have 84000000 want 84000032"
|
"error": "insufficient funds for gas * price + value: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B have 84000000 want 84000032"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"currentDifficulty": "0x20000",
|
||||||
|
"gasUsed": "0x0",
|
||||||
|
"currentBaseFee": "0x20"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
24
cmd/evm/testdata/14/readme.md
vendored
24
cmd/evm/testdata/14/readme.md
vendored
|
|
@ -5,36 +5,40 @@ This test shows how the `evm t8n` can be used to calculate the (ethash) difficul
|
||||||
Calculating it (with an empty set of txs) using `London` rules (and no provided unclehash for the parent block):
|
Calculating it (with an empty set of txs) using `London` rules (and no provided unclehash for the parent block):
|
||||||
```
|
```
|
||||||
[user@work evm]$ ./evm t8n --input.alloc=./testdata/14/alloc.json --input.txs=./testdata/14/txs.json --input.env=./testdata/14/env.json --output.result=stdout --state.fork=London
|
[user@work evm]$ ./evm t8n --input.alloc=./testdata/14/alloc.json --input.txs=./testdata/14/txs.json --input.env=./testdata/14/env.json --output.result=stdout --state.fork=London
|
||||||
INFO [08-30|20:43:09.352] Trie dumping started root=6f0588..7f4bdc
|
INFO [03-09|10:43:57.070] Trie dumping started root=6f0588..7f4bdc
|
||||||
INFO [08-30|20:43:09.352] Trie dumping complete accounts=2 elapsed="82.533µs"
|
INFO [03-09|10:43:57.070] Trie dumping complete accounts=2 elapsed="214.663µs"
|
||||||
INFO [08-30|20:43:09.352] Wrote file file=alloc.json
|
INFO [03-09|10:43:57.071] Wrote file file=alloc.json
|
||||||
{
|
{
|
||||||
"result": {
|
"result": {
|
||||||
"stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc",
|
"stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc",
|
||||||
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||||
"receiptRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||||
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"receipts": [],
|
"receipts": [],
|
||||||
"currentDifficulty": "0x2000020000000"
|
"currentDifficulty": "0x2000020000000",
|
||||||
|
"gasUsed": "0x0",
|
||||||
|
"currentBaseFee": "0x500"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Same thing, but this time providing a non-empty (and non-`emptyKeccak`) unclehash, which leads to a slightly different result:
|
Same thing, but this time providing a non-empty (and non-`emptyKeccak`) unclehash, which leads to a slightly different result:
|
||||||
```
|
```
|
||||||
[user@work evm]$ ./evm t8n --input.alloc=./testdata/14/alloc.json --input.txs=./testdata/14/txs.json --input.env=./testdata/14/env.uncles.json --output.result=stdout --state.fork=London
|
[user@work evm]$ ./evm t8n --input.alloc=./testdata/14/alloc.json --input.txs=./testdata/14/txs.json --input.env=./testdata/14/env.uncles.json --output.result=stdout --state.fork=London
|
||||||
INFO [08-30|20:44:33.102] Trie dumping started root=6f0588..7f4bdc
|
INFO [03-09|10:44:20.511] Trie dumping started root=6f0588..7f4bdc
|
||||||
INFO [08-30|20:44:33.102] Trie dumping complete accounts=2 elapsed="72.91µs"
|
INFO [03-09|10:44:20.511] Trie dumping complete accounts=2 elapsed="184.319µs"
|
||||||
INFO [08-30|20:44:33.102] Wrote file file=alloc.json
|
INFO [03-09|10:44:20.512] Wrote file file=alloc.json
|
||||||
{
|
{
|
||||||
"result": {
|
"result": {
|
||||||
"stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc",
|
"stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc",
|
||||||
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||||
"receiptRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||||
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||||
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"receipts": [],
|
"receipts": [],
|
||||||
"currentDifficulty": "0x1ff8020000000"
|
"currentDifficulty": "0x1ff8020000000",
|
||||||
|
"gasUsed": "0x0",
|
||||||
|
"currentBaseFee": "0x500"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
16
cmd/evm/testdata/19/readme.md
vendored
16
cmd/evm/testdata/19/readme.md
vendored
|
|
@ -6,4 +6,20 @@ this time on `GrayGlacier` (Eip 5133).
|
||||||
Calculating it (with an empty set of txs) using `GrayGlacier` rules (and no provided unclehash for the parent block):
|
Calculating it (with an empty set of txs) using `GrayGlacier` rules (and no provided unclehash for the parent block):
|
||||||
```
|
```
|
||||||
[user@work evm]$ ./evm t8n --input.alloc=./testdata/19/alloc.json --input.txs=./testdata/19/txs.json --input.env=./testdata/19/env.json --output.result=stdout --state.fork=GrayGlacier
|
[user@work evm]$ ./evm t8n --input.alloc=./testdata/19/alloc.json --input.txs=./testdata/19/txs.json --input.env=./testdata/19/env.json --output.result=stdout --state.fork=GrayGlacier
|
||||||
|
INFO [03-09|10:45:26.777] Trie dumping started root=6f0588..7f4bdc
|
||||||
|
INFO [03-09|10:45:26.777] Trie dumping complete accounts=2 elapsed="176.471µs"
|
||||||
|
INFO [03-09|10:45:26.777] Wrote file file=alloc.json
|
||||||
|
{
|
||||||
|
"result": {
|
||||||
|
"stateRoot": "0x6f058887ca01549716789c380ede95aecc510e6d1fdc4dbf67d053c7c07f4bdc",
|
||||||
|
"txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||||
|
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||||
|
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
|
||||||
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
"receipts": [],
|
||||||
|
"currentDifficulty": "0x2000000004000",
|
||||||
|
"gasUsed": "0x0",
|
||||||
|
"currentBaseFee": "0x500"
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
370
cmd/evm/testdata/7/readme.md
vendored
370
cmd/evm/testdata/7/readme.md
vendored
|
|
@ -3,5 +3,373 @@ DAO-transition works
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```
|
```
|
||||||
./statet8n --input.alloc=./testdata/7/alloc.json --input.txs=./testdata/7/txs.json --input.env=./testdata/7/env.json --output.alloc=stdout --state.fork=HomesteadToDaoAt5
|
./evm t8n --input.alloc=./testdata/7/alloc.json --input.txs=./testdata/7/txs.json --input.env=./testdata/7/env.json --output.alloc=stdout --state.fork=HomesteadToDaoAt5
|
||||||
|
INFO [03-09|10:47:37.255] Trie dumping started root=157847..2891b7
|
||||||
|
INFO [03-09|10:47:37.256] Trie dumping complete accounts=120 elapsed="715.635µs"
|
||||||
|
INFO [03-09|10:47:37.256] Wrote file file=result.json
|
||||||
|
{
|
||||||
|
"alloc": {
|
||||||
|
"0x005f5cee7a43331d5a3d3eec71305925a62f34b6": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x057b56736d32b86616a10f619859c6cd6f59092a": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x0737a6b837f97f46ebade41b9bc3e1c509c85c53": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x12e626b0eebfe86a56d633b9864e389b45dcb260": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x1591fc0f688c81fbeb17f5426a162a7024d430c2": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x17802f43a0137c506ba92291391a8a8f207f487d": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x1975bd06d486162d5dc297798dfc41edd5d160a7": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x1cba23d343a983e9b5cfd19496b9a9701ada385f": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x200450f06520bdd6c527622a273333384d870efb": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x23b75c2f6791eef49c69684db4c6c1f93bf49a50": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x24c4d950dfd4dd1902bbed3508144a54542bba94": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x253488078a4edf4d6f42f113d1e62836a942cf1a": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x27b137a85656544b1ccb5a0f2e561a5703c6a68f": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x2a5ed960395e2a49b1c758cef4aa15213cfd874c": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x304a554a310c7e546dfe434669c62820b7d83490": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x319f70bab6845585f412ec7724b744fec6095c85": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x3ba4d81db016dc2890c81f3acec2454bff5aada5": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x40b803a9abce16f50f36a77ba41180eb90023925": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x440c59b325d2997a134c2c7c60a8c61611212bad": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x4486a3d68fac6967006d7a517b889fd3f98c102b": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x47e7aa56d6bdf3f36be34619660de61275420af8": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x4863226780fe7c0356454236d3b1c8792785748d": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x492ea3bb0f3315521c31f273e565b868fc090f17": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x4deb0033bb26bc534b197e61d19e0733e5679784": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x4fa802324e929786dbda3b8820dc7834e9134a2a": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x4fd6ace747f06ece9c49699c7cabc62d02211f75": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x51e0ddd9998364a2eb38588679f0d2c42653e4a6": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x52c5317c848ba20c7504cb2c8052abd1fde29d03": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x542a9515200d14b68e934e9830d91645a980dd7a": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x5524c55fb03cf21f549444ccbecb664d0acad706": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x579a80d909f346fbfb1189493f521d7f48d52238": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x5c8536898fbb74fc7445814902fd08422eac56d0": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x5d2b2e6fcbe3b11d26b525e085ff818dae332479": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x5dc28b15dffed94048d73806ce4b7a4612a1d48f": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x6131c42fa982e56929107413a9d526fd99405560": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x6231b6d0d5e77fe001c2a460bd9584fee60d409b": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x627a0a960c079c21c34f7612d5d230e01b4ad4c7": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x63ed5a272de2f6d968408b4acb9024f4cc208ebf": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x6966ab0d485353095148a2155858910e0965b6f9": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x6d87578288b6cb5549d5076a207456a1f6a63dc0": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x6f6704e5a10332af6672e50b3d9754dc460dfa4d": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x779543a0491a837ca36ce8c635d6154e3c4911a6": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": {
|
||||||
|
"balance": "0xfeedbead"
|
||||||
|
},
|
||||||
|
"0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x97f43a37f595ab5dd318fb46e7a155eae057317a": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x9aa008f65de0b923a2a4f02012ad034a5e2e2192": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x9c15b54878ba618f494b38f0ae7443db6af648ba": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x9c50426be05db97f5d64fc54bf89eff947f0a321": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x9da397b9e80755301a3b32173283a91c0ef6c87e": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x9ea779f907f0b315b364b0cfc39a0fde5b02a416": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x9f27daea7aca0aa0446220b98d028715e3bc803d": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xa82f360a8d3455c5c41366975bde739c37bfeb8a": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||||
|
"balance": "0x5ffd4878be161d74",
|
||||||
|
"nonce": "0xac"
|
||||||
|
},
|
||||||
|
"0xac1ecab32727358dba8962a0f3b261731aad9723": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xacd87e28b0c9d1254e868b81cba4cc20d9a32225": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xadf80daec7ba8dcf15392f1ac611fff65d94f880": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xb136707642a4ea12fb4bae820f03d2562ebff487": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xb9637156d330c0d605a791f1c31ba5890582fe1c": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xbc07118b9ac290e4622f5e77a0853539789effbe": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xbe8539bfe837b67d1282b2b1d61c3f723966f049": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xbf4ed7b27f1d666546e30d74d50d173d20bca754": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xc4bbd073882dd2add2424cf47d35213405b01324": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xca544e5c4687d109611d0f8f928b53a25af72448": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xcc34673c6c40e791051898567a1222daf90be287": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xceaeb481747ca6c540a000c1f3641f8cef161fa7": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xd131637d5275fd1a68a3200f4ad25c71a2a9522e": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xd164b088bd9108b60d0ca3751da4bceb207b0782": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xd343b217de44030afaa275f54d31a9317c7f441e": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xda2fef9e4a3230988ff17df2165440f37e8b1708": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xe308bd1ac5fda103967359b2712dd89deffb7973": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xe4ae1efdfc53b73893af49113d8694a057b9c0d1": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xecd135fa4f61a655311e86238c92adcd779555d2": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xf0b1aa0eb660754448a7937c022e30aa692fe0c5": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xf1385fb24aad0cd7432824085e42aff90886fef5": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xf14c14075d6c4ed84b86798af0956deef67365b5": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xf4c64518ea10f995918a454158c6b61407ea345c": {
|
||||||
|
"balance": "0x0"
|
||||||
|
},
|
||||||
|
"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f": {
|
||||||
|
"balance": "0x0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
38
cmd/evm/testdata/8/readme.md
vendored
38
cmd/evm/testdata/8/readme.md
vendored
|
|
@ -23,41 +23,37 @@ There are three transactions, each invokes the contract above.
|
||||||
|
|
||||||
Running it yields:
|
Running it yields:
|
||||||
```
|
```
|
||||||
dir=./testdata/8 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace && cat trace-* | grep SLOAD
|
dir=./testdata/8 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace 2>/dev/null && cat trace-* | grep SLOAD
|
||||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Simlarly, we can provide the input transactions via `stdin` instead of as file:
|
Simlarly, we can provide the input transactions via `stdin` instead of as file:
|
||||||
|
|
||||||
```
|
```
|
||||||
dir=./testdata/8 \
|
$ dir=./testdata/8 \
|
||||||
&& cat $dir/txs.json | jq "{txs: .}" \
|
&& cat $dir/txs.json | jq "{txs: .}" \
|
||||||
| ./evm t8n --state.fork=Berlin \
|
| ./evm t8n --state.fork=Berlin \
|
||||||
--input.alloc=$dir/alloc.json \
|
--input.alloc=$dir/alloc.json \
|
||||||
--input.txs=stdin \
|
--input.txs=stdin \
|
||||||
--input.env=$dir/env.json \
|
--input.env=$dir/env.json \
|
||||||
--trace \
|
--trace \
|
||||||
|
2>/dev/null \
|
||||||
&& cat trace-* | grep SLOAD
|
&& cat trace-* | grep SLOAD
|
||||||
|
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x3"],"returnStack":[],"returnData":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If we try to execute it on older rules:
|
If we try to execute it on older rules:
|
||||||
```
|
```
|
||||||
dir=./testdata/8 && ./evm t8n --state.fork=Istanbul --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json
|
$ dir=./testdata/8 && ./evm t8n --state.fork=Istanbul --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json
|
||||||
INFO [01-21|23:21:51.265] rejected tx index=0 hash=d2818d..6ab3da error="tx type not supported"
|
ERROR(10): failed signing transactions: ERROR(10): tx 0: failed to sign tx: transaction type not supported
|
||||||
INFO [01-21|23:21:51.265] rejected tx index=1 hash=26ea00..81c01b from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="nonce too high: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B, tx: 1 state: 0"
|
|
||||||
INFO [01-21|23:21:51.265] rejected tx index=2 hash=698d01..369cee error="tx type not supported"
|
|
||||||
```
|
```
|
||||||
Number `1` and `3` are not applicable, and therefore number `2` has wrong nonce.
|
|
||||||
32
cmd/evm/testdata/9/readme.md
vendored
32
cmd/evm/testdata/9/readme.md
vendored
|
|
@ -22,20 +22,22 @@ There are two transactions, each invokes the contract above.
|
||||||
|
|
||||||
Running it yields:
|
Running it yields:
|
||||||
```
|
```
|
||||||
$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace && cat trace-* | grep SLOAD
|
$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace 2>/dev/null && cat trace-* | grep SLOAD
|
||||||
{"pc":2,"op":84,"gas":"0x48c28","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x1"],"returnStack":null,"returnD
|
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":4,"op":84,"gas":"0x47c86","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":3,"op":84,"gas":"0x483f4","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0","0x0"],"returnStack":null,"returnDa
|
{"pc":2,"op":84,"gas":"0x48c28","gasCost":"0x834","memSize":0,"stack":["0x0","0x1"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
ta":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":3,"op":84,"gas":"0x483f4","gasCost":"0x64","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":2,"op":84,"gas":"0x49cf4","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x1"],"returnStack":null,"returnD
|
{"pc":1,"op":84,"gas":"0x49cf6","gasCost":"0x834","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":4,"op":84,"gas":"0x494be","gasCost":"0x834","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
{"pc":3,"op":84,"gas":"0x494c0","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x0"],"returnStack":null,"returnD
|
{"pc":2,"op":84,"gas":"0x49cf4","gasCost":"0x834","memSize":0,"stack":["0x0","0x1"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""}
|
{"pc":3,"op":84,"gas":"0x494c0","gasCost":"0x834","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
|
{"pc":1,"op":84,"gas":"0x484be","gasCost":"0x64","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
|
{"pc":4,"op":84,"gas":"0x48456","gasCost":"0x64","memSize":0,"stack":["0x3"],"depth":1,"refund":0,"opName":"SLOAD"}
|
||||||
```
|
```
|
||||||
|
|
||||||
We can also get the post-alloc:
|
We can also get the post-alloc:
|
||||||
```
|
```
|
||||||
$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout
|
$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout 2>/dev/null
|
||||||
{
|
{
|
||||||
"alloc": {
|
"alloc": {
|
||||||
"0x000000000000000000000000000000000000aaaa": {
|
"0x000000000000000000000000000000000000aaaa": {
|
||||||
|
|
@ -65,10 +67,12 @@ by feeding it presigned transactions, located in `txs_signed.json`.
|
||||||
|
|
||||||
```
|
```
|
||||||
dir=./testdata/9 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs_signed.json --input.env=$dir/env.json
|
dir=./testdata/9 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs_signed.json --input.env=$dir/env.json
|
||||||
INFO [05-07|12:28:42.072] rejected tx index=0 hash=b4821e..536819 error="transaction type not supported"
|
WARN [03-09|11:06:22.065] rejected tx index=0 hash=334e09..f8dce5 error="transaction type not supported"
|
||||||
INFO [05-07|12:28:42.072] rejected tx index=1 hash=a9c6c6..fa4036 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="nonce too high: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B, tx: 1 state: 0"
|
INFO [03-09|11:06:22.066] rejected tx index=1 hash=a9c6c6..fa4036 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="nonce too high: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B, tx: 1 state: 0"
|
||||||
INFO [05-07|12:28:42.073] Wrote file file=alloc.json
|
INFO [03-09|11:06:22.066] Trie dumping started root=6eebe9..a0fda5
|
||||||
INFO [05-07|12:28:42.073] Wrote file file=result.json
|
INFO [03-09|11:06:22.066] Trie dumping complete accounts=2 elapsed="55.844µs"
|
||||||
|
INFO [03-09|11:06:22.066] Wrote file file=alloc.json
|
||||||
|
INFO [03-09|11:06:22.066] Wrote file file=result.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Number `0` is not applicable, and therefore number `1` has wrong nonce, and both are rejected.
|
Number `0` is not applicable, and therefore number `1` has wrong nonce, and both are rejected.
|
||||||
|
|
|
||||||
37
cmd/evm/testdata/9/txs_signed.json
vendored
Normal file
37
cmd/evm/testdata/9/txs_signed.json
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"gas": "0x4ef00",
|
||||||
|
"maxFeePerGas": "0x2",
|
||||||
|
"maxPriorityFeePerGas": "0x12A05F200",
|
||||||
|
"chainId": "0x1",
|
||||||
|
"input": "0x",
|
||||||
|
"nonce": "0x0",
|
||||||
|
"to": "0x000000000000000000000000000000000000aaaa",
|
||||||
|
"value": "0x0",
|
||||||
|
"type" : "0x2",
|
||||||
|
"accessList": [
|
||||||
|
{"address": "0x000000000000000000000000000000000000aaaa",
|
||||||
|
"storageKeys": [
|
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"v": "0x1",
|
||||||
|
"r": "0xd77c8ff989789b5d9d99254cbae2e2996dc7e6215cba4d55254c14e6d6b9f314",
|
||||||
|
"s": "0x5cc021481e7e6bb444bbb87ab32071e8fd0a8d1e125c7bb352d2879bd7ff5c0a",
|
||||||
|
"secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"gas": "0x4ef00",
|
||||||
|
"gasPrice": "0x12A05F200",
|
||||||
|
"chainId": "0x1",
|
||||||
|
"input": "0x",
|
||||||
|
"nonce": "0x1",
|
||||||
|
"to": "0x000000000000000000000000000000000000aaaa",
|
||||||
|
"value": "0x0",
|
||||||
|
"v": "0x25",
|
||||||
|
"r": "0xbee5ec9f6650020266bf3455a852eece2b073a2fa918c4d1836a1af69c2aa50c",
|
||||||
|
"s": "0x556c897a58dbc007a6b09814e1fba7502adb76effd2146da4365816926f387ce",
|
||||||
|
"secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
@ -694,41 +694,19 @@ func showMetaData(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Error accessing ancients: %v", err)
|
fmt.Fprintf(os.Stderr, "Error accessing ancients: %v", err)
|
||||||
}
|
}
|
||||||
pp := func(val *uint64) string {
|
data := rawdb.ReadChainMetadata(db)
|
||||||
if val == nil {
|
data = append(data, []string{"frozen", fmt.Sprintf("%d items", ancients)})
|
||||||
return "<nil>"
|
data = append(data, []string{"snapshotGenerator", snapshot.ParseGeneratorStatus(rawdb.ReadSnapshotGenerator(db))})
|
||||||
}
|
|
||||||
return fmt.Sprintf("%d (%#x)", *val, *val)
|
|
||||||
}
|
|
||||||
data := [][]string{
|
|
||||||
{"databaseVersion", pp(rawdb.ReadDatabaseVersion(db))},
|
|
||||||
{"headBlockHash", fmt.Sprintf("%v", rawdb.ReadHeadBlockHash(db))},
|
|
||||||
{"headFastBlockHash", fmt.Sprintf("%v", rawdb.ReadHeadFastBlockHash(db))},
|
|
||||||
{"headHeaderHash", fmt.Sprintf("%v", rawdb.ReadHeadHeaderHash(db))}}
|
|
||||||
if b := rawdb.ReadHeadBlock(db); b != nil {
|
if b := rawdb.ReadHeadBlock(db); b != nil {
|
||||||
data = append(data, []string{"headBlock.Hash", fmt.Sprintf("%v", b.Hash())})
|
data = append(data, []string{"headBlock.Hash", fmt.Sprintf("%v", b.Hash())})
|
||||||
data = append(data, []string{"headBlock.Root", fmt.Sprintf("%v", b.Root())})
|
data = append(data, []string{"headBlock.Root", fmt.Sprintf("%v", b.Root())})
|
||||||
data = append(data, []string{"headBlock.Number", fmt.Sprintf("%d (%#x)", b.Number(), b.Number())})
|
data = append(data, []string{"headBlock.Number", fmt.Sprintf("%d (%#x)", b.Number(), b.Number())})
|
||||||
}
|
}
|
||||||
if b := rawdb.ReadSkeletonSyncStatus(db); b != nil {
|
|
||||||
data = append(data, []string{"SkeletonSyncStatus", string(b)})
|
|
||||||
}
|
|
||||||
if h := rawdb.ReadHeadHeader(db); h != nil {
|
if h := rawdb.ReadHeadHeader(db); h != nil {
|
||||||
data = append(data, []string{"headHeader.Hash", fmt.Sprintf("%v", h.Hash())})
|
data = append(data, []string{"headHeader.Hash", fmt.Sprintf("%v", h.Hash())})
|
||||||
data = append(data, []string{"headHeader.Root", fmt.Sprintf("%v", h.Root)})
|
data = append(data, []string{"headHeader.Root", fmt.Sprintf("%v", h.Root)})
|
||||||
data = append(data, []string{"headHeader.Number", fmt.Sprintf("%d (%#x)", h.Number, h.Number)})
|
data = append(data, []string{"headHeader.Number", fmt.Sprintf("%d (%#x)", h.Number, h.Number)})
|
||||||
}
|
}
|
||||||
data = append(data, [][]string{{"frozen", fmt.Sprintf("%d items", ancients)},
|
|
||||||
{"lastPivotNumber", pp(rawdb.ReadLastPivotNumber(db))},
|
|
||||||
{"len(snapshotSyncStatus)", fmt.Sprintf("%d bytes", len(rawdb.ReadSnapshotSyncStatus(db)))},
|
|
||||||
{"snapshotGenerator", snapshot.ParseGeneratorStatus(rawdb.ReadSnapshotGenerator(db))},
|
|
||||||
{"snapshotDisabled", fmt.Sprintf("%v", rawdb.ReadSnapshotDisabled(db))},
|
|
||||||
{"snapshotJournal", fmt.Sprintf("%d bytes", len(rawdb.ReadSnapshotJournal(db)))},
|
|
||||||
{"snapshotRecoveryNumber", pp(rawdb.ReadSnapshotRecoveryNumber(db))},
|
|
||||||
{"snapshotRoot", fmt.Sprintf("%v", rawdb.ReadSnapshotRoot(db))},
|
|
||||||
{"txIndexTail", pp(rawdb.ReadTxIndexTail(db))},
|
|
||||||
{"fastTxLookupLimit", pp(rawdb.ReadFastTxLookupLimit(db))},
|
|
||||||
}...)
|
|
||||||
table := tablewriter.NewWriter(os.Stdout)
|
table := tablewriter.NewWriter(os.Stdout)
|
||||||
table.SetHeader([]string{"Field", "Value"})
|
table.SetHeader([]string{"Field", "Value"})
|
||||||
table.AppendBulk(data)
|
table.AppendBulk(data)
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -156,6 +156,11 @@ func (b *BlockGen) Number() *big.Int {
|
||||||
return new(big.Int).Set(b.header.Number)
|
return new(big.Int).Set(b.header.Number)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Timestamp returns the timestamp of the block being generated.
|
||||||
|
func (b *BlockGen) Timestamp() uint64 {
|
||||||
|
return b.header.Time
|
||||||
|
}
|
||||||
|
|
||||||
// BaseFee returns the EIP-1559 base fee of the block being generated.
|
// BaseFee returns the EIP-1559 base fee of the block being generated.
|
||||||
func (b *BlockGen) BaseFee() *big.Int {
|
func (b *BlockGen) BaseFee() *big.Int {
|
||||||
return new(big.Int).Set(b.header.BaseFee)
|
return new(big.Int).Set(b.header.BaseFee)
|
||||||
|
|
|
||||||
|
|
@ -70,10 +70,10 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEVMTxContext creates a new transaction context for a single transaction.
|
// NewEVMTxContext creates a new transaction context for a single transaction.
|
||||||
func NewEVMTxContext(msg Message) vm.TxContext {
|
func NewEVMTxContext(msg *Message) vm.TxContext {
|
||||||
return vm.TxContext{
|
return vm.TxContext{
|
||||||
Origin: msg.From(),
|
Origin: msg.From,
|
||||||
GasPrice: new(big.Int).Set(msg.GasPrice()),
|
GasPrice: new(big.Int).Set(msg.GasPrice),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -308,7 +308,7 @@ func TestValidation(t *testing.T) {
|
||||||
|
|
||||||
// Local is mainnet Gray Glacier, and isn't aware of more forks. Remote announces Gray Glacier +
|
// Local is mainnet Gray Glacier, and isn't aware of more forks. Remote announces Gray Glacier +
|
||||||
// 0xffffffff. Local needs software update, reject.
|
// 0xffffffff. Local needs software update, reject.
|
||||||
{×tampedConfig, 15050000, 0, ID{Hash: checksumToBytes(checksumUpdate(0xf0afd0e3, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale},
|
{params.MainnetChainConfig, 15050000, 0, ID{Hash: checksumToBytes(checksumUpdate(0xf0afd0e3, math.MaxUint64)), Next: 0}, ErrLocalIncompatibleOrStale},
|
||||||
|
|
||||||
// Local is mainnet Gray Glacier, and is aware of Shanghai. Remote announces Shanghai +
|
// Local is mainnet Gray Glacier, and is aware of Shanghai. Remote announces Shanghai +
|
||||||
// 0xffffffff. Local needs software update, reject.
|
// 0xffffffff. Local needs software update, reject.
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||||
// Create the idle freezer instance
|
// Create the idle freezer instance
|
||||||
frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly)
|
frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
printChainMetadata(db)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Since the freezer can be stored separately from the user's key-value database,
|
// Since the freezer can be stored separately from the user's key-value database,
|
||||||
|
|
@ -234,8 +235,10 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||||
// the freezer and the key-value store.
|
// the freezer and the key-value store.
|
||||||
frgenesis, err := frdb.Ancient(ChainFreezerHashTable, 0)
|
frgenesis, err := frdb.Ancient(ChainFreezerHashTable, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
printChainMetadata(db)
|
||||||
return nil, fmt.Errorf("failed to retrieve genesis from ancient %v", err)
|
return nil, fmt.Errorf("failed to retrieve genesis from ancient %v", err)
|
||||||
} else if !bytes.Equal(kvgenesis, frgenesis) {
|
} else if !bytes.Equal(kvgenesis, frgenesis) {
|
||||||
|
printChainMetadata(db)
|
||||||
return nil, fmt.Errorf("genesis mismatch: %#x (leveldb) != %#x (ancients)", kvgenesis, frgenesis)
|
return nil, fmt.Errorf("genesis mismatch: %#x (leveldb) != %#x (ancients)", kvgenesis, frgenesis)
|
||||||
}
|
}
|
||||||
// Key-value store and freezer belong to the same network. Ensure that they
|
// Key-value store and freezer belong to the same network. Ensure that they
|
||||||
|
|
@ -243,8 +246,19 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||||
if kvhash, _ := db.Get(headerHashKey(frozen)); len(kvhash) == 0 {
|
if kvhash, _ := db.Get(headerHashKey(frozen)); len(kvhash) == 0 {
|
||||||
// Subsequent header after the freezer limit is missing from the database.
|
// Subsequent header after the freezer limit is missing from the database.
|
||||||
// Reject startup if the database has a more recent head.
|
// Reject startup if the database has a more recent head.
|
||||||
if ldbNum := *ReadHeaderNumber(db, ReadHeadHeaderHash(db)); ldbNum > frozen-1 {
|
if head := *ReadHeaderNumber(db, ReadHeadHeaderHash(db)); head > frozen-1 {
|
||||||
return nil, fmt.Errorf("gap in the chain between ancients (#%d) and leveldb (#%d) ", frozen, ldbNum)
|
// Find the smallest block stored in the key-value store
|
||||||
|
// in range of [frozen, head]
|
||||||
|
var number uint64
|
||||||
|
for number = frozen; number <= head; number++ {
|
||||||
|
if present, _ := db.Has(headerHashKey(number)); present {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We are about to exit on error. Print database metdata beore exiting
|
||||||
|
printChainMetadata(db)
|
||||||
|
return nil, fmt.Errorf("gap in the chain between ancients [0 - #%d] and leveldb [#%d - #%d] ",
|
||||||
|
frozen-1, number, head)
|
||||||
}
|
}
|
||||||
// Database contains only older data than the freezer, this happens if the
|
// Database contains only older data than the freezer, this happens if the
|
||||||
// state was wiped and reinited from an existing freezer.
|
// state was wiped and reinited from an existing freezer.
|
||||||
|
|
@ -261,6 +275,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||||
// Key-value store contains more data than the genesis block, make sure we
|
// Key-value store contains more data than the genesis block, make sure we
|
||||||
// didn't freeze anything yet.
|
// didn't freeze anything yet.
|
||||||
if kvblob, _ := db.Get(headerHashKey(1)); len(kvblob) == 0 {
|
if kvblob, _ := db.Get(headerHashKey(1)); len(kvblob) == 0 {
|
||||||
|
printChainMetadata(db)
|
||||||
return nil, errors.New("ancient chain segments already extracted, please set --datadir.ancient to the correct path")
|
return nil, errors.New("ancient chain segments already extracted, please set --datadir.ancient to the correct path")
|
||||||
}
|
}
|
||||||
// Block #1 is still in the database, we're allowed to init a new freezer
|
// Block #1 is still in the database, we're allowed to init a new freezer
|
||||||
|
|
@ -583,3 +598,42 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// printChainMetadata prints out chain metadata to stderr.
|
||||||
|
func printChainMetadata(db ethdb.KeyValueStore) {
|
||||||
|
fmt.Fprintf(os.Stderr, "Chain metadata\n")
|
||||||
|
for _, v := range ReadChainMetadata(db) {
|
||||||
|
fmt.Fprintf(os.Stderr, " %s\n", strings.Join(v, ": "))
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadChainMetadata returns a set of key/value pairs that contains informatin
|
||||||
|
// about the database chain status. This can be used for diagnostic purposes
|
||||||
|
// when investigating the state of the node.
|
||||||
|
func ReadChainMetadata(db ethdb.KeyValueStore) [][]string {
|
||||||
|
pp := func(val *uint64) string {
|
||||||
|
if val == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d (%#x)", *val, *val)
|
||||||
|
}
|
||||||
|
data := [][]string{
|
||||||
|
{"databaseVersion", pp(ReadDatabaseVersion(db))},
|
||||||
|
{"headBlockHash", fmt.Sprintf("%v", ReadHeadBlockHash(db))},
|
||||||
|
{"headFastBlockHash", fmt.Sprintf("%v", ReadHeadFastBlockHash(db))},
|
||||||
|
{"headHeaderHash", fmt.Sprintf("%v", ReadHeadHeaderHash(db))},
|
||||||
|
{"lastPivotNumber", pp(ReadLastPivotNumber(db))},
|
||||||
|
{"len(snapshotSyncStatus)", fmt.Sprintf("%d bytes", len(ReadSnapshotSyncStatus(db)))},
|
||||||
|
{"snapshotDisabled", fmt.Sprintf("%v", ReadSnapshotDisabled(db))},
|
||||||
|
{"snapshotJournal", fmt.Sprintf("%d bytes", len(ReadSnapshotJournal(db)))},
|
||||||
|
{"snapshotRecoveryNumber", pp(ReadSnapshotRecoveryNumber(db))},
|
||||||
|
{"snapshotRoot", fmt.Sprintf("%v", ReadSnapshotRoot(db))},
|
||||||
|
{"txIndexTail", pp(ReadTxIndexTail(db))},
|
||||||
|
{"fastTxLookupLimit", pp(ReadFastTxLookupLimit(db))},
|
||||||
|
}
|
||||||
|
if b := ReadSkeletonSyncStatus(db); b != nil {
|
||||||
|
data = append(data, []string{"SkeletonSyncStatus", string(b)})
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Convert the transaction into an executable message and pre-cache its sender
|
// Convert the transaction into an executable message and pre-cache its sender
|
||||||
msg, err := tx.AsMessage(signer, header.BaseFee)
|
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return // Also invalid block, bail out
|
return // Also invalid block, bail out
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +85,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
||||||
// precacheTransaction attempts to apply a transaction to the given state database
|
// precacheTransaction attempts to apply a transaction to the given state database
|
||||||
// and uses the input parameters for its environment. The goal is not to execute
|
// and uses the input parameters for its environment. The goal is not to execute
|
||||||
// the transaction successfully, rather to warm up touched data slots.
|
// the transaction successfully, rather to warm up touched data slots.
|
||||||
func precacheTransaction(msg types.Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error {
|
func precacheTransaction(msg *Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error {
|
||||||
// Update the evm with the new transaction context.
|
// Update the evm with the new transaction context.
|
||||||
evm.Reset(NewEVMTxContext(msg), statedb)
|
evm.Reset(NewEVMTxContext(msg), statedb)
|
||||||
// Add addresses to access list if applicable
|
// Add addresses to access list if applicable
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
cfg.Debug = true
|
cfg.Debug = true
|
||||||
}
|
}
|
||||||
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
|
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
|
||||||
msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee)
|
msg, err := TransactionToMessage(tx, types.MakeSigner(p.config, header.Number), header.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +121,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
return receipts, allLogs, *usedGas, nil
|
return receipts, allLogs, *usedGas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
|
func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
|
||||||
// Create a new context to be used in the EVM environment.
|
// Create a new context to be used in the EVM environment.
|
||||||
txContext := NewEVMTxContext(msg)
|
txContext := NewEVMTxContext(msg)
|
||||||
evm.Reset(txContext, statedb)
|
evm.Reset(txContext, statedb)
|
||||||
|
|
@ -153,7 +153,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool
|
||||||
receipt.GasUsed = result.UsedGas
|
receipt.GasUsed = result.UsedGas
|
||||||
|
|
||||||
// If the transaction created a contract, store the creation address in the receipt.
|
// If the transaction created a contract, store the creation address in the receipt.
|
||||||
if msg.To() == nil {
|
if msg.To == nil {
|
||||||
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,7 +171,7 @@ func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool
|
||||||
// for the transaction, gas used and an error if the transaction failed,
|
// for the transaction, gas used and an error if the transaction failed,
|
||||||
// indicating the block was invalid.
|
// indicating the block was invalid.
|
||||||
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
|
func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) {
|
||||||
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number), header.BaseFee)
|
msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number), header.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,10 @@ import (
|
||||||
cmath "github.com/ethereum/go-ethereum/common/math"
|
cmath "github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
var emptyCodeHash = crypto.Keccak256Hash(nil)
|
var emptyCodeHash = crypto.Keccak256Hash(nil)
|
||||||
|
|
||||||
// StateTransition represents a state transition.
|
// StateTransition represents a state transition.
|
||||||
|
|
@ -85,6 +85,8 @@ type Message interface {
|
||||||
AccessList() types.AccessList
|
AccessList() types.AccessList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> v1.11.4
|
||||||
// ExecutionResult includes all output after executing given evm
|
// ExecutionResult includes all output after executing given evm
|
||||||
// message no matter the execution itself is successful or not.
|
// message no matter the execution itself is successful or not.
|
||||||
type ExecutionResult struct {
|
type ExecutionResult struct {
|
||||||
|
|
@ -179,19 +181,47 @@ func toWordSize(size uint64) uint64 {
|
||||||
return (size + 31) / 32
|
return (size + 31) / 32
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStateTransition initialises and returns a new state transition object.
|
// A Message contains the data derived from a single transaction that is relevant to state
|
||||||
func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
|
// processing.
|
||||||
return &StateTransition{
|
type Message struct {
|
||||||
gp: gp,
|
To *common.Address
|
||||||
evm: evm,
|
From common.Address
|
||||||
msg: msg,
|
Nonce uint64
|
||||||
gasPrice: msg.GasPrice(),
|
Value *big.Int
|
||||||
gasFeeCap: msg.GasFeeCap(),
|
GasLimit uint64
|
||||||
gasTipCap: msg.GasTipCap(),
|
GasPrice *big.Int
|
||||||
value: msg.Value(),
|
GasFeeCap *big.Int
|
||||||
data: msg.Data(),
|
GasTipCap *big.Int
|
||||||
state: evm.StateDB,
|
Data []byte
|
||||||
|
AccessList types.AccessList
|
||||||
|
|
||||||
|
// When SkipAccountCheckss is true, the message nonce is not checked against the
|
||||||
|
// account nonce in state. It also disables checking that the sender is an EOA.
|
||||||
|
// This field will be set to true for operations like RPC eth_call.
|
||||||
|
SkipAccountChecks bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TransactionToMessage converts a transaction into a Message.
|
||||||
|
func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.Int) (*Message, error) {
|
||||||
|
msg := &Message{
|
||||||
|
Nonce: tx.Nonce(),
|
||||||
|
GasLimit: tx.Gas(),
|
||||||
|
GasPrice: new(big.Int).Set(tx.GasPrice()),
|
||||||
|
GasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
|
||||||
|
GasTipCap: new(big.Int).Set(tx.GasTipCap()),
|
||||||
|
To: tx.To(),
|
||||||
|
Value: tx.Value(),
|
||||||
|
Data: tx.Data(),
|
||||||
|
AccessList: tx.AccessList(),
|
||||||
|
SkipAccountChecks: false,
|
||||||
|
}
|
||||||
|
// If baseFee provided, set gasPrice to effectiveGasPrice.
|
||||||
|
if baseFee != nil {
|
||||||
|
msg.GasPrice = cmath.BigMin(msg.GasPrice.Add(msg.GasTipCap, baseFee), msg.GasFeeCap)
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
msg.From, err = types.Sender(s, tx)
|
||||||
|
return msg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyMessage computes the new state by applying the given message
|
// ApplyMessage computes the new state by applying the given message
|
||||||
|
|
@ -201,94 +231,137 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
|
||||||
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
||||||
// indicates a core error meaning that the message would always fail for that particular
|
// indicates a core error meaning that the message would always fail for that particular
|
||||||
// state and would never be accepted within a block.
|
// state and would never be accepted within a block.
|
||||||
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) {
|
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) {
|
||||||
return NewStateTransition(evm, msg, gp).TransitionDb()
|
return NewStateTransition(evm, msg, gp).TransitionDb()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StateTransition represents a state transition.
|
||||||
|
//
|
||||||
|
// == The State Transitioning Model
|
||||||
|
//
|
||||||
|
// A state transition is a change made when a transaction is applied to the current world
|
||||||
|
// state. The state transitioning model does all the necessary work to work out a valid new
|
||||||
|
// state root.
|
||||||
|
//
|
||||||
|
// 1. Nonce handling
|
||||||
|
// 2. Pre pay gas
|
||||||
|
// 3. Create a new state object if the recipient is nil
|
||||||
|
// 4. Value transfer
|
||||||
|
//
|
||||||
|
// == If contract creation ==
|
||||||
|
//
|
||||||
|
// 4a. Attempt to run transaction data
|
||||||
|
// 4b. If valid, use result as code for the new state object
|
||||||
|
//
|
||||||
|
// == end ==
|
||||||
|
//
|
||||||
|
// 5. Run Script section
|
||||||
|
// 6. Derive new state root
|
||||||
|
type StateTransition struct {
|
||||||
|
gp *GasPool
|
||||||
|
msg *Message
|
||||||
|
gasRemaining uint64
|
||||||
|
initialGas uint64
|
||||||
|
state vm.StateDB
|
||||||
|
evm *vm.EVM
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStateTransition initialises and returns a new state transition object.
|
||||||
|
func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition {
|
||||||
|
return &StateTransition{
|
||||||
|
gp: gp,
|
||||||
|
evm: evm,
|
||||||
|
msg: msg,
|
||||||
|
state: evm.StateDB,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// to returns the recipient of the message.
|
// to returns the recipient of the message.
|
||||||
func (st *StateTransition) to() common.Address {
|
func (st *StateTransition) to() common.Address {
|
||||||
if st.msg == nil || st.msg.To() == nil /* contract creation */ {
|
if st.msg == nil || st.msg.To == nil /* contract creation */ {
|
||||||
return common.Address{}
|
return common.Address{}
|
||||||
}
|
}
|
||||||
return *st.msg.To()
|
return *st.msg.To
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) buyGas() error {
|
func (st *StateTransition) buyGas() error {
|
||||||
mgval := new(big.Int).SetUint64(st.msg.Gas())
|
mgval := new(big.Int).SetUint64(st.msg.GasLimit)
|
||||||
mgval = mgval.Mul(mgval, st.gasPrice)
|
mgval = mgval.Mul(mgval, st.msg.GasPrice)
|
||||||
if st.evm.Config.PreExec {
|
if st.evm.Config.PreExec {
|
||||||
mgval = big.NewInt(0)
|
mgval = big.NewInt(0)
|
||||||
}
|
}
|
||||||
balanceCheck := mgval
|
balanceCheck := mgval
|
||||||
if st.gasFeeCap != nil {
|
if st.msg.GasFeeCap != nil {
|
||||||
balanceCheck = new(big.Int).SetUint64(st.msg.Gas())
|
balanceCheck = new(big.Int).SetUint64(st.msg.GasLimit)
|
||||||
balanceCheck = balanceCheck.Mul(balanceCheck, st.gasFeeCap)
|
balanceCheck = balanceCheck.Mul(balanceCheck, st.msg.GasFeeCap)
|
||||||
if st.evm.Config.PreExec {
|
if st.evm.Config.PreExec {
|
||||||
balanceCheck = big.NewInt(0)
|
balanceCheck = big.NewInt(0)
|
||||||
}
|
}
|
||||||
balanceCheck.Add(balanceCheck, st.value)
|
balanceCheck.Add(balanceCheck, st.msg.Value)
|
||||||
}
|
}
|
||||||
if have, want := st.state.GetBalance(st.msg.From()), balanceCheck; have.Cmp(want) < 0 {
|
if have, want := st.state.GetBalance(st.msg.From), balanceCheck; have.Cmp(want) < 0 {
|
||||||
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From().Hex(), have, want)
|
return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, st.msg.From.Hex(), have, want)
|
||||||
}
|
}
|
||||||
if err := st.gp.SubGas(st.msg.Gas()); err != nil {
|
if err := st.gp.SubGas(st.msg.GasLimit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
st.gas += st.msg.Gas()
|
st.gasRemaining += st.msg.GasLimit
|
||||||
|
|
||||||
st.initialGas = st.msg.Gas()
|
st.initialGas = st.msg.GasLimit
|
||||||
st.state.SubBalance(st.msg.From(), mgval)
|
st.state.SubBalance(st.msg.From, mgval)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) preCheck() error {
|
func (st *StateTransition) preCheck() error {
|
||||||
// Only check transactions that are not fake
|
// Only check transactions that are not fake
|
||||||
if !st.msg.IsFake() {
|
msg := st.msg
|
||||||
|
if !msg.SkipAccountChecks {
|
||||||
// Make sure this transaction's nonce is correct.
|
// Make sure this transaction's nonce is correct.
|
||||||
stNonce := st.state.GetNonce(st.msg.From())
|
stNonce := st.state.GetNonce(msg.From)
|
||||||
if msgNonce := st.msg.Nonce(); stNonce < msgNonce {
|
if msgNonce := msg.Nonce; stNonce < msgNonce {
|
||||||
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
|
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
|
||||||
st.msg.From().Hex(), msgNonce, stNonce)
|
msg.From.Hex(), msgNonce, stNonce)
|
||||||
} else if stNonce > msgNonce {
|
} else if stNonce > msgNonce {
|
||||||
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
|
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
|
||||||
st.msg.From().Hex(), msgNonce, stNonce)
|
msg.From.Hex(), msgNonce, stNonce)
|
||||||
} else if stNonce+1 < stNonce {
|
} else if stNonce+1 < stNonce {
|
||||||
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
|
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
|
||||||
st.msg.From().Hex(), stNonce)
|
msg.From.Hex(), stNonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pre exec tx not check sender
|
// pre exec tx not check sender
|
||||||
// pre exec for gnosis safe address
|
// pre exec for gnosis safe address
|
||||||
if !st.msg.IsPre() {
|
if !st.msg.IsPre() {
|
||||||
// Make sure the sender is an EOA
|
// Make sure the sender is an EOA
|
||||||
if codeHash := st.state.GetCodeHash(st.msg.From()); codeHash != emptyCodeHash && codeHash != (common.Hash{}) {
|
codeHash := st.state.GetCodeHash(msg.From)
|
||||||
|
if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash {
|
||||||
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
|
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
|
||||||
st.msg.From().Hex(), codeHash)
|
msg.From.Hex(), codeHash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
|
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
|
||||||
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) && !st.msg.IsPre() {
|
if st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) && !st.msg.IsPre() {
|
||||||
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
|
// Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call)
|
||||||
if !st.evm.Config.NoBaseFee || st.gasFeeCap.BitLen() > 0 || st.gasTipCap.BitLen() > 0 {
|
if !st.evm.Config.NoBaseFee || msg.GasFeeCap.BitLen() > 0 || msg.GasTipCap.BitLen() > 0 {
|
||||||
if l := st.gasFeeCap.BitLen(); l > 256 {
|
if l := msg.GasFeeCap.BitLen(); l > 256 {
|
||||||
return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
|
return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
|
||||||
st.msg.From().Hex(), l)
|
msg.From.Hex(), l)
|
||||||
}
|
}
|
||||||
if l := st.gasTipCap.BitLen(); l > 256 {
|
if l := msg.GasTipCap.BitLen(); l > 256 {
|
||||||
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh,
|
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh,
|
||||||
st.msg.From().Hex(), l)
|
msg.From.Hex(), l)
|
||||||
}
|
}
|
||||||
if st.gasFeeCap.Cmp(st.gasTipCap) < 0 {
|
if msg.GasFeeCap.Cmp(msg.GasTipCap) < 0 {
|
||||||
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap,
|
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap,
|
||||||
st.msg.From().Hex(), st.gasTipCap, st.gasFeeCap)
|
msg.From.Hex(), msg.GasTipCap, msg.GasFeeCap)
|
||||||
}
|
}
|
||||||
// This will panic if baseFee is nil, but basefee presence is verified
|
// This will panic if baseFee is nil, but basefee presence is verified
|
||||||
// as part of header validation.
|
// as part of header validation.
|
||||||
if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
|
if msg.GasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
|
||||||
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
|
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
|
||||||
st.msg.From().Hex(), st.gasFeeCap, st.evm.Context.BaseFee)
|
msg.From.Hex(), msg.GasFeeCap, st.evm.Context.BaseFee)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -324,52 +397,52 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
if st.evm.Config.Debug {
|
if st.evm.Config.Debug {
|
||||||
st.evm.Config.Tracer.CaptureTxStart(st.initialGas)
|
st.evm.Config.Tracer.CaptureTxStart(st.initialGas)
|
||||||
defer func() {
|
defer func() {
|
||||||
st.evm.Config.Tracer.CaptureTxEnd(st.gas)
|
st.evm.Config.Tracer.CaptureTxEnd(st.gasRemaining)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
msg = st.msg
|
msg = st.msg
|
||||||
sender = vm.AccountRef(msg.From())
|
sender = vm.AccountRef(msg.From)
|
||||||
rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time)
|
rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil, st.evm.Context.Time)
|
||||||
contractCreation = msg.To() == nil
|
contractCreation = msg.To == nil
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check clauses 4-5, subtract intrinsic gas if everything is correct
|
// Check clauses 4-5, subtract intrinsic gas if everything is correct
|
||||||
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
|
gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if st.gas < gas {
|
if st.gasRemaining < gas {
|
||||||
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas)
|
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
|
||||||
}
|
}
|
||||||
st.gas -= gas
|
st.gasRemaining -= gas
|
||||||
|
|
||||||
// Check clause 6
|
// Check clause 6
|
||||||
if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) {
|
if msg.Value.Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From, msg.Value) {
|
||||||
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex())
|
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the init code size has been exceeded.
|
// Check whether the init code size has been exceeded.
|
||||||
if rules.IsShanghai && contractCreation && len(st.data) > params.MaxInitCodeSize {
|
if rules.IsShanghai && contractCreation && len(msg.Data) > params.MaxInitCodeSize {
|
||||||
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize)
|
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the preparatory steps for state transition which includes:
|
// Execute the preparatory steps for state transition which includes:
|
||||||
// - prepare accessList(post-berlin)
|
// - prepare accessList(post-berlin)
|
||||||
// - reset transient storage(eip 1153)
|
// - reset transient storage(eip 1153)
|
||||||
st.state.Prepare(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
|
st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ret []byte
|
ret []byte
|
||||||
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
|
vmerr error // vm errors do not effect consensus and are therefore not assigned to err
|
||||||
)
|
)
|
||||||
if contractCreation {
|
if contractCreation {
|
||||||
ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value)
|
ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, msg.Value)
|
||||||
} else {
|
} else {
|
||||||
// Increment the nonce for the next transaction
|
// Increment the nonce for the next transaction
|
||||||
st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
|
st.state.SetNonce(msg.From, st.state.GetNonce(sender.Address())+1)
|
||||||
ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value)
|
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !rules.IsLondon {
|
if !rules.IsLondon {
|
||||||
|
|
@ -379,12 +452,12 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
// After EIP-3529: refunds are capped to gasUsed / 5
|
// After EIP-3529: refunds are capped to gasUsed / 5
|
||||||
st.refundGas(params.RefundQuotientEIP3529)
|
st.refundGas(params.RefundQuotientEIP3529)
|
||||||
}
|
}
|
||||||
effectiveTip := st.gasPrice
|
effectiveTip := msg.GasPrice
|
||||||
if rules.IsLondon {
|
if rules.IsLondon {
|
||||||
effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee))
|
effectiveTip = cmath.BigMin(msg.GasTipCap, new(big.Int).Sub(msg.GasFeeCap, st.evm.Context.BaseFee))
|
||||||
}
|
}
|
||||||
|
|
||||||
if st.evm.Config.NoBaseFee && st.gasFeeCap.Sign() == 0 && st.gasTipCap.Sign() == 0 {
|
if st.evm.Config.NoBaseFee && msg.GasFeeCap.Sign() == 0 && msg.GasTipCap.Sign() == 0 {
|
||||||
// Skip fee payment when NoBaseFee is set and the fee fields
|
// Skip fee payment when NoBaseFee is set and the fee fields
|
||||||
// are 0. This avoids a negative effectiveTip being applied to
|
// are 0. This avoids a negative effectiveTip being applied to
|
||||||
// the coinbase when simulating calls.
|
// the coinbase when simulating calls.
|
||||||
|
|
@ -407,21 +480,21 @@ func (st *StateTransition) refundGas(refundQuotient uint64) {
|
||||||
if refund > st.state.GetRefund() {
|
if refund > st.state.GetRefund() {
|
||||||
refund = st.state.GetRefund()
|
refund = st.state.GetRefund()
|
||||||
}
|
}
|
||||||
st.gas += refund
|
st.gasRemaining += refund
|
||||||
|
|
||||||
// Return ETH for remaining gas, exchanged at the original rate.
|
// Return ETH for remaining gas, exchanged at the original rate.
|
||||||
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
|
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice)
|
||||||
if st.evm.Config.PreExec {
|
if st.evm.Config.PreExec {
|
||||||
remaining = new(big.Int).SetUint64(0)
|
remaining = new(big.Int).SetUint64(0)
|
||||||
}
|
}
|
||||||
st.state.AddBalance(st.msg.From(), remaining)
|
st.state.AddBalance(st.msg.From, remaining)
|
||||||
|
|
||||||
// Also return remaining gas to the block gas counter so it is
|
// Also return remaining gas to the block gas counter so it is
|
||||||
// available for the next transaction.
|
// available for the next transaction.
|
||||||
st.gp.AddGas(st.gas)
|
st.gp.AddGas(st.gasRemaining)
|
||||||
}
|
}
|
||||||
|
|
||||||
// gasUsed returns the amount of gas used up by the state transition.
|
// gasUsed returns the amount of gas used up by the state transition.
|
||||||
func (st *StateTransition) gasUsed() uint64 {
|
func (st *StateTransition) gasUsed() uint64 {
|
||||||
return st.initialGas - st.gas
|
return st.initialGas - st.gasRemaining
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,7 @@ type list struct {
|
||||||
|
|
||||||
costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance)
|
costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance)
|
||||||
gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit)
|
gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit)
|
||||||
|
totalcost *big.Int // Total cost of all transactions in the list
|
||||||
}
|
}
|
||||||
|
|
||||||
// newList create a new transaction list for maintaining nonce-indexable fast,
|
// newList create a new transaction list for maintaining nonce-indexable fast,
|
||||||
|
|
@ -265,6 +266,7 @@ func newList(strict bool) *list {
|
||||||
strict: strict,
|
strict: strict,
|
||||||
txs: newSortedMap(),
|
txs: newSortedMap(),
|
||||||
costcap: new(big.Int),
|
costcap: new(big.Int),
|
||||||
|
totalcost: new(big.Int),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -302,7 +304,11 @@ func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transa
|
||||||
if tx.GasFeeCapIntCmp(thresholdFeeCap) < 0 || tx.GasTipCapIntCmp(thresholdTip) < 0 {
|
if tx.GasFeeCapIntCmp(thresholdFeeCap) < 0 || tx.GasTipCapIntCmp(thresholdTip) < 0 {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
// Old is being replaced, subtract old cost
|
||||||
|
l.subTotalCost([]*types.Transaction{old})
|
||||||
}
|
}
|
||||||
|
// Add new tx cost to totalcost
|
||||||
|
l.totalcost.Add(l.totalcost, tx.Cost())
|
||||||
// Otherwise overwrite the old transaction with the current one
|
// Otherwise overwrite the old transaction with the current one
|
||||||
l.txs.Put(tx)
|
l.txs.Put(tx)
|
||||||
if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 {
|
if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 {
|
||||||
|
|
@ -318,7 +324,9 @@ func (l *list) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transa
|
||||||
// provided threshold. Every removed transaction is returned for any post-removal
|
// provided threshold. Every removed transaction is returned for any post-removal
|
||||||
// maintenance.
|
// maintenance.
|
||||||
func (l *list) Forward(threshold uint64) types.Transactions {
|
func (l *list) Forward(threshold uint64) types.Transactions {
|
||||||
return l.txs.Forward(threshold)
|
txs := l.txs.Forward(threshold)
|
||||||
|
l.subTotalCost(txs)
|
||||||
|
return txs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter removes all transactions from the list with a cost or gas limit higher
|
// Filter removes all transactions from the list with a cost or gas limit higher
|
||||||
|
|
@ -357,6 +365,9 @@ func (l *list) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions,
|
||||||
}
|
}
|
||||||
invalids = l.txs.filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest })
|
invalids = l.txs.filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest })
|
||||||
}
|
}
|
||||||
|
// Reset total cost
|
||||||
|
l.subTotalCost(removed)
|
||||||
|
l.subTotalCost(invalids)
|
||||||
l.txs.reheap()
|
l.txs.reheap()
|
||||||
return removed, invalids
|
return removed, invalids
|
||||||
}
|
}
|
||||||
|
|
@ -364,7 +375,9 @@ func (l *list) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions,
|
||||||
// Cap places a hard limit on the number of items, returning all transactions
|
// Cap places a hard limit on the number of items, returning all transactions
|
||||||
// exceeding that limit.
|
// exceeding that limit.
|
||||||
func (l *list) Cap(threshold int) types.Transactions {
|
func (l *list) Cap(threshold int) types.Transactions {
|
||||||
return l.txs.Cap(threshold)
|
txs := l.txs.Cap(threshold)
|
||||||
|
l.subTotalCost(txs)
|
||||||
|
return txs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove deletes a transaction from the maintained list, returning whether the
|
// Remove deletes a transaction from the maintained list, returning whether the
|
||||||
|
|
@ -376,9 +389,12 @@ func (l *list) Remove(tx *types.Transaction) (bool, types.Transactions) {
|
||||||
if removed := l.txs.Remove(nonce); !removed {
|
if removed := l.txs.Remove(nonce); !removed {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
l.subTotalCost([]*types.Transaction{tx})
|
||||||
// In strict mode, filter out non-executable transactions
|
// In strict mode, filter out non-executable transactions
|
||||||
if l.strict {
|
if l.strict {
|
||||||
return true, l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce })
|
txs := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce })
|
||||||
|
l.subTotalCost(txs)
|
||||||
|
return true, txs
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
@ -391,7 +407,9 @@ func (l *list) Remove(tx *types.Transaction) (bool, types.Transactions) {
|
||||||
// prevent getting into and invalid state. This is not something that should ever
|
// prevent getting into and invalid state. This is not something that should ever
|
||||||
// happen but better to be self correcting than failing!
|
// happen but better to be self correcting than failing!
|
||||||
func (l *list) Ready(start uint64) types.Transactions {
|
func (l *list) Ready(start uint64) types.Transactions {
|
||||||
return l.txs.Ready(start)
|
txs := l.txs.Ready(start)
|
||||||
|
l.subTotalCost(txs)
|
||||||
|
return txs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Len returns the length of the transaction list.
|
// Len returns the length of the transaction list.
|
||||||
|
|
@ -417,6 +435,14 @@ func (l *list) LastElement() *types.Transaction {
|
||||||
return l.txs.LastElement()
|
return l.txs.LastElement()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// subTotalCost subtracts the cost of the given transactions from the
|
||||||
|
// total cost of all transactions.
|
||||||
|
func (l *list) subTotalCost(txs []*types.Transaction) {
|
||||||
|
for _, tx := range txs {
|
||||||
|
l.totalcost.Sub(l.totalcost, tx.Cost())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// priceHeap is a heap.Interface implementation over transactions for retrieving
|
// priceHeap is a heap.Interface implementation over transactions for retrieving
|
||||||
// price-sorted transactions to discard when the pool fills up. If baseFee is set
|
// price-sorted transactions to discard when the pool fills up. If baseFee is set
|
||||||
// then the heap is sorted based on the effective tip based on the given base fee.
|
// then the heap is sorted based on the effective tip based on the given base fee.
|
||||||
|
|
@ -561,6 +587,7 @@ func (l *pricedList) underpricedFor(h *priceHeap, tx *types.Transaction) bool {
|
||||||
|
|
||||||
// Discard finds a number of most underpriced transactions, removes them from the
|
// Discard finds a number of most underpriced transactions, removes them from the
|
||||||
// priced list and returns them for further removal from the entire pool.
|
// priced list and returns them for further removal from the entire pool.
|
||||||
|
// If noPending is set to true, we will only consider the floating list
|
||||||
//
|
//
|
||||||
// Note local transaction won't be considered for eviction.
|
// Note local transaction won't be considered for eviction.
|
||||||
func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) {
|
func (l *pricedList) Discard(slots int, force bool) (types.Transactions, bool) {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package txpool
|
package txpool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"container/heap"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
@ -87,6 +88,14 @@ var (
|
||||||
// than some meaningful limit a user might use. This is not a consensus error
|
// than some meaningful limit a user might use. This is not a consensus error
|
||||||
// making the transaction invalid, rather a DOS protection.
|
// making the transaction invalid, rather a DOS protection.
|
||||||
ErrOversizedData = errors.New("oversized data")
|
ErrOversizedData = errors.New("oversized data")
|
||||||
|
|
||||||
|
// ErrFutureReplacePending is returned if a future transaction replaces a pending
|
||||||
|
// transaction. Future transactions should only be able to replace other future transactions.
|
||||||
|
ErrFutureReplacePending = errors.New("future transaction tries to replace pending")
|
||||||
|
|
||||||
|
// ErrOverdraft is returned if a transaction would cause the senders balance to go negative
|
||||||
|
// thus invalidating a potential large number of transactions.
|
||||||
|
ErrOverdraft = errors.New("transaction would cause overdraft")
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -639,9 +648,25 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
|
||||||
}
|
}
|
||||||
// Transactor should have enough funds to cover the costs
|
// Transactor should have enough funds to cover the costs
|
||||||
// cost == V + GP * GL
|
// cost == V + GP * GL
|
||||||
if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 {
|
balance := pool.currentState.GetBalance(from)
|
||||||
|
if balance.Cmp(tx.Cost()) < 0 {
|
||||||
return core.ErrInsufficientFunds
|
return core.ErrInsufficientFunds
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify that replacing transactions will not result in overdraft
|
||||||
|
list := pool.pending[from]
|
||||||
|
if list != nil { // Sender already has pending txs
|
||||||
|
sum := new(big.Int).Add(tx.Cost(), list.totalcost)
|
||||||
|
if repl := list.txs.Get(tx.Nonce()); repl != nil {
|
||||||
|
// Deduct the cost of a transaction replaced by this
|
||||||
|
sum.Sub(sum, repl.Cost())
|
||||||
|
}
|
||||||
|
if balance.Cmp(sum) < 0 {
|
||||||
|
log.Trace("Replacing transactions would overdraft", "sender", from, "balance", pool.currentState.GetBalance(from), "required", sum)
|
||||||
|
return ErrOverdraft
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the transaction has more gas than the basic tx fee.
|
// Ensure the transaction has more gas than the basic tx fee.
|
||||||
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai)
|
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.istanbul, pool.shanghai)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -678,6 +703,10 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
|
||||||
invalidTxMeter.Mark(1)
|
invalidTxMeter.Mark(1)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// already validated by this point
|
||||||
|
from, _ := types.Sender(pool.signer, tx)
|
||||||
|
|
||||||
// If the transaction pool is full, discard underpriced transactions
|
// If the transaction pool is full, discard underpriced transactions
|
||||||
if uint64(pool.all.Slots()+numSlots(tx)) > pool.config.GlobalSlots+pool.config.GlobalQueue {
|
if uint64(pool.all.Slots()+numSlots(tx)) > pool.config.GlobalSlots+pool.config.GlobalQueue {
|
||||||
// If the new transaction is underpriced, don't accept it
|
// If the new transaction is underpriced, don't accept it
|
||||||
|
|
@ -686,6 +715,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
|
||||||
underpricedTxMeter.Mark(1)
|
underpricedTxMeter.Mark(1)
|
||||||
return false, ErrUnderpriced
|
return false, ErrUnderpriced
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're about to replace a transaction. The reorg does a more thorough
|
// We're about to replace a transaction. The reorg does a more thorough
|
||||||
// analysis of what to remove and how, but it runs async. We don't want to
|
// analysis of what to remove and how, but it runs async. We don't want to
|
||||||
// do too many replacements between reorg-runs, so we cap the number of
|
// do too many replacements between reorg-runs, so we cap the number of
|
||||||
|
|
@ -706,17 +736,37 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
|
||||||
overflowedTxMeter.Mark(1)
|
overflowedTxMeter.Mark(1)
|
||||||
return false, ErrTxPoolOverflow
|
return false, ErrTxPoolOverflow
|
||||||
}
|
}
|
||||||
// Bump the counter of rejections-since-reorg
|
|
||||||
pool.changesSinceReorg += len(drop)
|
// If the new transaction is a future transaction it should never churn pending transactions
|
||||||
|
if pool.isFuture(from, tx) {
|
||||||
|
var replacesPending bool
|
||||||
|
for _, dropTx := range drop {
|
||||||
|
dropSender, _ := types.Sender(pool.signer, dropTx)
|
||||||
|
if list := pool.pending[dropSender]; list != nil && list.Overlaps(dropTx) {
|
||||||
|
replacesPending = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add all transactions back to the priced queue
|
||||||
|
if replacesPending {
|
||||||
|
for _, dropTx := range drop {
|
||||||
|
heap.Push(&pool.priced.urgent, dropTx)
|
||||||
|
}
|
||||||
|
log.Trace("Discarding future transaction replacing pending tx", "hash", hash)
|
||||||
|
return false, ErrFutureReplacePending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Kick out the underpriced remote transactions.
|
// Kick out the underpriced remote transactions.
|
||||||
for _, tx := range drop {
|
for _, tx := range drop {
|
||||||
log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
||||||
underpricedTxMeter.Mark(1)
|
underpricedTxMeter.Mark(1)
|
||||||
pool.removeTx(tx.Hash(), false)
|
dropped := pool.removeTx(tx.Hash(), false)
|
||||||
|
pool.changesSinceReorg += dropped
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to replace an existing transaction in the pending pool
|
// Try to replace an existing transaction in the pending pool
|
||||||
from, _ := types.Sender(pool.signer, tx) // already validated
|
|
||||||
if list := pool.pending[from]; list != nil && list.Overlaps(tx) {
|
if list := pool.pending[from]; list != nil && list.Overlaps(tx) {
|
||||||
// Nonce already pending, check if required price bump is met
|
// Nonce already pending, check if required price bump is met
|
||||||
inserted, old := list.Add(tx, pool.config.PriceBump)
|
inserted, old := list.Add(tx, pool.config.PriceBump)
|
||||||
|
|
@ -760,6 +810,20 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (replaced bool, err e
|
||||||
return replaced, nil
|
return replaced, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isFuture reports whether the given transaction is immediately executable.
|
||||||
|
func (pool *TxPool) isFuture(from common.Address, tx *types.Transaction) bool {
|
||||||
|
list := pool.pending[from]
|
||||||
|
if list == nil {
|
||||||
|
return pool.pendingNonces.get(from) != tx.Nonce()
|
||||||
|
}
|
||||||
|
// Sender has pending transactions.
|
||||||
|
if old := list.txs.Get(tx.Nonce()); old != nil {
|
||||||
|
return false // It replaces a pending transaction.
|
||||||
|
}
|
||||||
|
// Not replacing, check if parent nonce exists in pending.
|
||||||
|
return list.txs.Get(tx.Nonce()-1) == nil
|
||||||
|
}
|
||||||
|
|
||||||
// enqueueTx inserts a new transaction into the non-executable transaction queue.
|
// enqueueTx inserts a new transaction into the non-executable transaction queue.
|
||||||
//
|
//
|
||||||
// Note, this method assumes the pool lock is held!
|
// Note, this method assumes the pool lock is held!
|
||||||
|
|
@ -996,11 +1060,12 @@ func (pool *TxPool) Has(hash common.Hash) bool {
|
||||||
|
|
||||||
// removeTx removes a single transaction from the queue, moving all subsequent
|
// removeTx removes a single transaction from the queue, moving all subsequent
|
||||||
// transactions back to the future queue.
|
// transactions back to the future queue.
|
||||||
func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
|
// Returns the number of transactions removed from the pending queue.
|
||||||
|
func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) int {
|
||||||
// Fetch the transaction we wish to delete
|
// Fetch the transaction we wish to delete
|
||||||
tx := pool.all.Get(hash)
|
tx := pool.all.Get(hash)
|
||||||
if tx == nil {
|
if tx == nil {
|
||||||
return
|
return 0
|
||||||
}
|
}
|
||||||
addr, _ := types.Sender(pool.signer, tx) // already validated during insertion
|
addr, _ := types.Sender(pool.signer, tx) // already validated during insertion
|
||||||
|
|
||||||
|
|
@ -1028,7 +1093,7 @@ func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
|
||||||
pool.pendingNonces.setIfLower(addr, tx.Nonce())
|
pool.pendingNonces.setIfLower(addr, tx.Nonce())
|
||||||
// Reduce the pending counter
|
// Reduce the pending counter
|
||||||
pendingGauge.Dec(int64(1 + len(invalids)))
|
pendingGauge.Dec(int64(1 + len(invalids)))
|
||||||
return
|
return 1 + len(invalids)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Transaction is in the future queue
|
// Transaction is in the future queue
|
||||||
|
|
@ -1042,6 +1107,7 @@ func (pool *TxPool) removeTx(hash common.Hash, outofbound bool) {
|
||||||
delete(pool.beats, addr)
|
delete(pool.beats, addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// requestReset requests a pool reset to the new head block.
|
// requestReset requests a pool reset to the new head block.
|
||||||
|
|
|
||||||
212
core/txpool/txpool2_test.go
Normal file
212
core/txpool/txpool2_test.go
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
package txpool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
)
|
||||||
|
|
||||||
|
func pricedValuedTransaction(nonce uint64, value int64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
|
||||||
|
tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(value), gaslimit, gasprice, nil), types.HomesteadSigner{}, key)
|
||||||
|
return tx
|
||||||
|
}
|
||||||
|
|
||||||
|
func count(t *testing.T, pool *TxPool) (pending int, queued int) {
|
||||||
|
t.Helper()
|
||||||
|
pending, queued = pool.stats()
|
||||||
|
if err := validatePoolInternals(pool); err != nil {
|
||||||
|
t.Fatalf("pool internal state corrupted: %v", err)
|
||||||
|
}
|
||||||
|
return pending, queued
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillPool(t *testing.T, pool *TxPool) {
|
||||||
|
t.Helper()
|
||||||
|
// Create a number of test accounts, fund them and make transactions
|
||||||
|
executableTxs := types.Transactions{}
|
||||||
|
nonExecutableTxs := types.Transactions{}
|
||||||
|
for i := 0; i < 384; i++ {
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000))
|
||||||
|
// Add executable ones
|
||||||
|
for j := 0; j < int(pool.config.AccountSlots); j++ {
|
||||||
|
executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Import the batch and verify that limits have been enforced
|
||||||
|
pool.AddRemotesSync(executableTxs)
|
||||||
|
pool.AddRemotesSync(nonExecutableTxs)
|
||||||
|
pending, queued := pool.Stats()
|
||||||
|
slots := pool.all.Slots()
|
||||||
|
// sanity-check that the test prerequisites are ok (pending full)
|
||||||
|
if have, want := pending, slots; have != want {
|
||||||
|
t.Fatalf("have %d, want %d", have, want)
|
||||||
|
}
|
||||||
|
if have, want := queued, 0; have != want {
|
||||||
|
t.Fatalf("have %d, want %d", have, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("pool.config: GlobalSlots=%d, GlobalQueue=%d\n", pool.config.GlobalSlots, pool.config.GlobalQueue)
|
||||||
|
t.Logf("pending: %d queued: %d, all: %d\n", pending, queued, slots)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that if a batch high-priced of non-executables arrive, they do not kick out
|
||||||
|
// executable transactions
|
||||||
|
func TestTransactionFutureAttack(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Create the pool to test the limit enforcement with
|
||||||
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||||
|
blockchain := &testBlockChain{1000000, statedb, new(event.Feed)}
|
||||||
|
config := testTxPoolConfig
|
||||||
|
config.GlobalQueue = 100
|
||||||
|
config.GlobalSlots = 100
|
||||||
|
pool := NewTxPool(config, eip1559Config, blockchain)
|
||||||
|
defer pool.Stop()
|
||||||
|
fillPool(t, pool)
|
||||||
|
pending, _ := pool.Stats()
|
||||||
|
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||||
|
{
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||||
|
futureTxs := types.Transactions{}
|
||||||
|
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
|
||||||
|
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key))
|
||||||
|
}
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
pool.AddRemotesSync(futureTxs)
|
||||||
|
newPending, newQueued := count(t, pool)
|
||||||
|
t.Logf("pending: %d queued: %d, all: %d\n", newPending, newQueued, pool.all.Slots())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newPending, _ := pool.Stats()
|
||||||
|
// Pending should not have been touched
|
||||||
|
if have, want := newPending, pending; have < want {
|
||||||
|
t.Errorf("wrong pending-count, have %d, want %d (GlobalSlots: %d)",
|
||||||
|
have, want, pool.config.GlobalSlots)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that if a batch high-priced of non-executables arrive, they do not kick out
|
||||||
|
// executable transactions
|
||||||
|
func TestTransactionFuture1559(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// Create the pool to test the pricing enforcement with
|
||||||
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||||
|
blockchain := &testBlockChain{1000000, statedb, new(event.Feed)}
|
||||||
|
pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain)
|
||||||
|
defer pool.Stop()
|
||||||
|
|
||||||
|
// Create a number of test accounts, fund them and make transactions
|
||||||
|
fillPool(t, pool)
|
||||||
|
pending, _ := pool.Stats()
|
||||||
|
|
||||||
|
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
|
||||||
|
{
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||||
|
futureTxs := types.Transactions{}
|
||||||
|
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
|
||||||
|
futureTxs = append(futureTxs, dynamicFeeTx(1000+uint64(j), 100000, big.NewInt(200), big.NewInt(101), key))
|
||||||
|
}
|
||||||
|
pool.AddRemotesSync(futureTxs)
|
||||||
|
}
|
||||||
|
newPending, _ := pool.Stats()
|
||||||
|
// Pending should not have been touched
|
||||||
|
if have, want := newPending, pending; have != want {
|
||||||
|
t.Errorf("Wrong pending-count, have %d, want %d (GlobalSlots: %d)",
|
||||||
|
have, want, pool.config.GlobalSlots)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that if a batch of balance-overdraft txs arrive, they do not kick out
|
||||||
|
// executable transactions
|
||||||
|
func TestTransactionZAttack(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// Create the pool to test the pricing enforcement with
|
||||||
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||||
|
blockchain := &testBlockChain{1000000, statedb, new(event.Feed)}
|
||||||
|
pool := NewTxPool(testTxPoolConfig, eip1559Config, blockchain)
|
||||||
|
defer pool.Stop()
|
||||||
|
// Create a number of test accounts, fund them and make transactions
|
||||||
|
fillPool(t, pool)
|
||||||
|
|
||||||
|
countInvalidPending := func() int {
|
||||||
|
t.Helper()
|
||||||
|
var ivpendingNum int
|
||||||
|
pendingtxs, _ := pool.Content()
|
||||||
|
for account, txs := range pendingtxs {
|
||||||
|
cur_balance := new(big.Int).Set(pool.currentState.GetBalance(account))
|
||||||
|
for _, tx := range txs {
|
||||||
|
if cur_balance.Cmp(tx.Value()) <= 0 {
|
||||||
|
ivpendingNum++
|
||||||
|
} else {
|
||||||
|
cur_balance.Sub(cur_balance, tx.Value())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := validatePoolInternals(pool); err != nil {
|
||||||
|
t.Fatalf("pool internal state corrupted: %v", err)
|
||||||
|
}
|
||||||
|
return ivpendingNum
|
||||||
|
}
|
||||||
|
ivPending := countInvalidPending()
|
||||||
|
t.Logf("invalid pending: %d\n", ivPending)
|
||||||
|
|
||||||
|
// Now, DETER-Z attack starts, let's add a bunch of expensive non-executables (from N accounts) along with balance-overdraft txs (from one account), and see if the pending-count drops
|
||||||
|
for j := 0; j < int(pool.config.GlobalQueue); j++ {
|
||||||
|
futureTxs := types.Transactions{}
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||||
|
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key))
|
||||||
|
pool.AddRemotesSync(futureTxs)
|
||||||
|
}
|
||||||
|
|
||||||
|
overDraftTxs := types.Transactions{}
|
||||||
|
{
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
|
||||||
|
for j := 0; j < int(pool.config.GlobalSlots); j++ {
|
||||||
|
overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 60000000000, 21000, big.NewInt(500), key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pool.AddRemotesSync(overDraftTxs)
|
||||||
|
pool.AddRemotesSync(overDraftTxs)
|
||||||
|
pool.AddRemotesSync(overDraftTxs)
|
||||||
|
pool.AddRemotesSync(overDraftTxs)
|
||||||
|
pool.AddRemotesSync(overDraftTxs)
|
||||||
|
|
||||||
|
newPending, newQueued := count(t, pool)
|
||||||
|
newIvPending := countInvalidPending()
|
||||||
|
t.Logf("pool.all.Slots(): %d\n", pool.all.Slots())
|
||||||
|
t.Logf("pending: %d queued: %d, all: %d\n", newPending, newQueued, pool.all.Slots())
|
||||||
|
t.Logf("invalid pending: %d\n", newIvPending)
|
||||||
|
|
||||||
|
// Pending should not have been touched
|
||||||
|
if newIvPending != ivPending {
|
||||||
|
t.Errorf("Wrong invalid pending-count, have %d, want %d (GlobalSlots: %d, queued: %d)",
|
||||||
|
newIvPending, ivPending, pool.config.GlobalSlots, newQueued)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -158,6 +158,9 @@ func validatePoolInternals(pool *TxPool) error {
|
||||||
if nonce := pool.pendingNonces.get(addr); nonce != last+1 {
|
if nonce := pool.pendingNonces.get(addr); nonce != last+1 {
|
||||||
return fmt.Errorf("pending nonce mismatch: have %v, want %v", nonce, last+1)
|
return fmt.Errorf("pending nonce mismatch: have %v, want %v", nonce, last+1)
|
||||||
}
|
}
|
||||||
|
if txs.totalcost.Cmp(common.Big0) < 0 {
|
||||||
|
return fmt.Errorf("totalcost went negative: %v", txs.totalcost)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -1105,7 +1108,7 @@ func TestPendingLimiting(t *testing.T) {
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
testAddBalance(pool, account, big.NewInt(1000000))
|
testAddBalance(pool, account, big.NewInt(1000000000000))
|
||||||
|
|
||||||
// Keep track of transaction events to ensure all executables get announced
|
// Keep track of transaction events to ensure all executables get announced
|
||||||
events := make(chan core.NewTxsEvent, testTxPoolConfig.AccountQueue+5)
|
events := make(chan core.NewTxsEvent, testTxPoolConfig.AccountQueue+5)
|
||||||
|
|
@ -1584,7 +1587,7 @@ func TestRepricingKeepsLocals(t *testing.T) {
|
||||||
keys := make([]*ecdsa.PrivateKey, 3)
|
keys := make([]*ecdsa.PrivateKey, 3)
|
||||||
for i := 0; i < len(keys); i++ {
|
for i := 0; i < len(keys); i++ {
|
||||||
keys[i], _ = crypto.GenerateKey()
|
keys[i], _ = crypto.GenerateKey()
|
||||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000*1000000))
|
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(100000*1000000))
|
||||||
}
|
}
|
||||||
// Create transaction (both pending and queued) with a linearly growing gasprice
|
// Create transaction (both pending and queued) with a linearly growing gasprice
|
||||||
for i := uint64(0); i < 500; i++ {
|
for i := uint64(0); i < 500; i++ {
|
||||||
|
|
@ -1663,7 +1666,7 @@ func TestUnderpricing(t *testing.T) {
|
||||||
defer sub.Unsubscribe()
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
// Create a number of test accounts and fund them
|
// Create a number of test accounts and fund them
|
||||||
keys := make([]*ecdsa.PrivateKey, 4)
|
keys := make([]*ecdsa.PrivateKey, 5)
|
||||||
for i := 0; i < len(keys); i++ {
|
for i := 0; i < len(keys); i++ {
|
||||||
keys[i], _ = crypto.GenerateKey()
|
keys[i], _ = crypto.GenerateKey()
|
||||||
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
testAddBalance(pool, crypto.PubkeyToAddress(keys[i].PublicKey), big.NewInt(1000000))
|
||||||
|
|
@ -1699,6 +1702,10 @@ func TestUnderpricing(t *testing.T) {
|
||||||
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced {
|
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced {
|
||||||
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced)
|
||||||
}
|
}
|
||||||
|
// Replace a future transaction with a future transaction
|
||||||
|
if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(2), keys[1])); err != nil { // +K1:1 => -K1:1 => Pend K0:0, K0:1, K2:0; Que K1:1
|
||||||
|
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||||
|
}
|
||||||
// Ensure that adding high priced transactions drops cheap ones, but not own
|
// Ensure that adding high priced transactions drops cheap ones, but not own
|
||||||
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { // +K1:0 => -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que -
|
if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { // +K1:0 => -K1:1 => Pend K0:0, K0:1, K1:0, K2:0; Que -
|
||||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||||
|
|
@ -1709,6 +1716,10 @@ func TestUnderpricing(t *testing.T) {
|
||||||
if err := pool.AddRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:3 => -K0:1 => Pend K1:0, K2:0; Que K1:2 K1:3
|
if err := pool.AddRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { // +K1:3 => -K0:1 => Pend K1:0, K2:0; Que K1:2 K1:3
|
||||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
// Ensure that replacing a pending transaction with a future transaction fails
|
||||||
|
if err := pool.AddRemote(pricedTransaction(5, 100000, big.NewInt(6), keys[1])); err != ErrFutureReplacePending {
|
||||||
|
t.Fatalf("adding future replace transaction error mismatch: have %v, want %v", err, ErrFutureReplacePending)
|
||||||
|
}
|
||||||
pending, queued = pool.Stats()
|
pending, queued = pool.Stats()
|
||||||
if pending != 2 {
|
if pending != 2 {
|
||||||
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
t.Fatalf("pending transactions mismatched: have %d, want %d", pending, 2)
|
||||||
|
|
@ -1716,7 +1727,7 @@ func TestUnderpricing(t *testing.T) {
|
||||||
if queued != 2 {
|
if queued != 2 {
|
||||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
|
||||||
}
|
}
|
||||||
if err := validateEvents(events, 1); err != nil {
|
if err := validateEvents(events, 2); err != nil {
|
||||||
t.Fatalf("additional event firing failed: %v", err)
|
t.Fatalf("additional event firing failed: %v", err)
|
||||||
}
|
}
|
||||||
if err := validatePoolInternals(pool); err != nil {
|
if err := validatePoolInternals(pool); err != nil {
|
||||||
|
|
@ -1878,11 +1889,11 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
||||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tx = pricedTransaction(2, 100000, big.NewInt(3), keys[1])
|
tx = pricedTransaction(1, 100000, big.NewInt(3), keys[1])
|
||||||
if err := pool.AddRemote(tx); err != nil { // +K1:2, -K0:1 => Pend K0:0 K1:0, K2:0; Que K1:2
|
if err := pool.AddRemote(tx); err != nil { // +K1:2, -K0:1 => Pend K0:0 K1:0, K2:0; Que K1:2
|
||||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||||
}
|
}
|
||||||
tx = dynamicFeeTx(3, 100000, big.NewInt(4), big.NewInt(1), keys[1])
|
tx = dynamicFeeTx(2, 100000, big.NewInt(4), big.NewInt(1), keys[1])
|
||||||
if err := pool.AddRemote(tx); err != nil { // +K1:3, -K1:0 => Pend K0:0 K2:0; Que K1:2 K1:3
|
if err := pool.AddRemote(tx); err != nil { // +K1:3, -K1:0 => Pend K0:0 K2:0; Que K1:2 K1:3
|
||||||
t.Fatalf("failed to add well priced transaction: %v", err)
|
t.Fatalf("failed to add well priced transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1893,7 +1904,7 @@ func TestUnderpricingDynamicFee(t *testing.T) {
|
||||||
if queued != 2 {
|
if queued != 2 {
|
||||||
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
|
t.Fatalf("queued transactions mismatched: have %d, want %d", queued, 2)
|
||||||
}
|
}
|
||||||
if err := validateEvents(events, 1); err != nil {
|
if err := validateEvents(events, 2); err != nil {
|
||||||
t.Fatalf("additional event firing failed: %v", err)
|
t.Fatalf("additional event firing failed: %v", err)
|
||||||
}
|
}
|
||||||
if err := validatePoolInternals(pool); err != nil {
|
if err := validatePoolInternals(pool); err != nil {
|
||||||
|
|
@ -2487,7 +2498,7 @@ func benchmarkBatchInsert(b *testing.B, size int, local bool) {
|
||||||
defer pool.Stop()
|
defer pool.Stop()
|
||||||
|
|
||||||
account := crypto.PubkeyToAddress(key.PublicKey)
|
account := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
testAddBalance(pool, account, big.NewInt(1000000))
|
testAddBalance(pool, account, big.NewInt(1000000000000000000))
|
||||||
|
|
||||||
batches := make([]types.Transactions, b.N)
|
batches := make([]types.Transactions, b.N)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
|
|
|
||||||
|
|
@ -589,77 +589,6 @@ func (t *TransactionsByPriceAndNonce) Pop() {
|
||||||
heap.Pop(&t.heads)
|
heap.Pop(&t.heads)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message is a fully derived transaction and implements core.Message
|
|
||||||
//
|
|
||||||
// NOTE: In a future PR this will be removed.
|
|
||||||
type Message struct {
|
|
||||||
to *common.Address
|
|
||||||
from common.Address
|
|
||||||
nonce uint64
|
|
||||||
amount *big.Int
|
|
||||||
gasLimit uint64
|
|
||||||
gasPrice *big.Int
|
|
||||||
gasFeeCap *big.Int
|
|
||||||
gasTipCap *big.Int
|
|
||||||
data []byte
|
|
||||||
accessList AccessList
|
|
||||||
isFake bool
|
|
||||||
isPre bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice, gasFeeCap, gasTipCap *big.Int, data []byte, accessList AccessList, isFake bool, isPre bool) Message {
|
|
||||||
return Message{
|
|
||||||
from: from,
|
|
||||||
to: to,
|
|
||||||
nonce: nonce,
|
|
||||||
amount: amount,
|
|
||||||
gasLimit: gasLimit,
|
|
||||||
gasPrice: gasPrice,
|
|
||||||
gasFeeCap: gasFeeCap,
|
|
||||||
gasTipCap: gasTipCap,
|
|
||||||
data: data,
|
|
||||||
accessList: accessList,
|
|
||||||
isFake: isFake,
|
|
||||||
isPre: isPre,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AsMessage returns the transaction as a core.Message.
|
|
||||||
func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
|
|
||||||
msg := Message{
|
|
||||||
nonce: tx.Nonce(),
|
|
||||||
gasLimit: tx.Gas(),
|
|
||||||
gasPrice: new(big.Int).Set(tx.GasPrice()),
|
|
||||||
gasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
|
|
||||||
gasTipCap: new(big.Int).Set(tx.GasTipCap()),
|
|
||||||
to: tx.To(),
|
|
||||||
amount: tx.Value(),
|
|
||||||
data: tx.Data(),
|
|
||||||
accessList: tx.AccessList(),
|
|
||||||
isFake: false,
|
|
||||||
}
|
|
||||||
// If baseFee provided, set gasPrice to effectiveGasPrice.
|
|
||||||
if baseFee != nil {
|
|
||||||
msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.gasTipCap, baseFee), msg.gasFeeCap)
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
msg.from, err = Sender(s, tx)
|
|
||||||
return msg, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Message) From() common.Address { return m.from }
|
|
||||||
func (m Message) To() *common.Address { return m.to }
|
|
||||||
func (m Message) GasPrice() *big.Int { return m.gasPrice }
|
|
||||||
func (m Message) GasFeeCap() *big.Int { return m.gasFeeCap }
|
|
||||||
func (m Message) GasTipCap() *big.Int { return m.gasTipCap }
|
|
||||||
func (m Message) Value() *big.Int { return m.amount }
|
|
||||||
func (m Message) Gas() uint64 { return m.gasLimit }
|
|
||||||
func (m Message) Nonce() uint64 { return m.nonce }
|
|
||||||
func (m Message) Data() []byte { return m.data }
|
|
||||||
func (m Message) AccessList() AccessList { return m.accessList }
|
|
||||||
func (m Message) IsFake() bool { return m.isFake }
|
|
||||||
func (m Message) IsPre() bool { return m.isPre }
|
|
||||||
|
|
||||||
// copyAddressPtr copies an address.
|
// copyAddressPtr copies an address.
|
||||||
func copyAddressPtr(a *common.Address) *common.Address {
|
func copyAddressPtr(a *common.Address) *common.Address {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto/bls12381"
|
"github.com/ethereum/go-ethereum/crypto/bls12381"
|
||||||
"github.com/ethereum/go-ethereum/crypto/bn256"
|
"github.com/ethereum/go-ethereum/crypto/bn256"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
big2 "github.com/holiman/big"
|
|
||||||
"golang.org/x/crypto/ripemd160"
|
"golang.org/x/crypto/ripemd160"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -378,9 +377,9 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
// Retrieve the operands and execute the exponentiation
|
// Retrieve the operands and execute the exponentiation
|
||||||
var (
|
var (
|
||||||
base = new(big2.Int).SetBytes(getData(input, 0, baseLen))
|
base = new(big.Int).SetBytes(getData(input, 0, baseLen))
|
||||||
exp = new(big2.Int).SetBytes(getData(input, baseLen, expLen))
|
exp = new(big.Int).SetBytes(getData(input, baseLen, expLen))
|
||||||
mod = new(big2.Int).SetBytes(getData(input, baseLen+expLen, modLen))
|
mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen))
|
||||||
v []byte
|
v []byte
|
||||||
)
|
)
|
||||||
switch {
|
switch {
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
|
||||||
return params.NetSstoreDirtyGas, nil
|
return params.NetSstoreDirtyGas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here come the EIP220 rules:
|
// Here come the EIP2200 rules:
|
||||||
//
|
//
|
||||||
// (0.) If *gasleft* is less than or equal to 2300, fail the current call.
|
// (0.) If *gasleft* is less than or equal to 2300, fail the current call.
|
||||||
// (1.) If current value equals new value (this is a no-op), SLOAD_GAS is deducted.
|
// (1.) If current value equals new value (this is a no-op), SLOAD_GAS is deducted.
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,7 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
||||||
if vmConfig == nil {
|
if vmConfig == nil {
|
||||||
vmConfig = b.eth.blockchain.GetVMConfig()
|
vmConfig = b.eth.blockchain.GetVMConfig()
|
||||||
}
|
}
|
||||||
|
|
@ -391,6 +391,6 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re
|
||||||
return b.eth.StateAtBlock(ctx, block, reexec, base, readOnly, preferDisk)
|
return b.eth.StateAtBlock(ctx, block, reexec, base, readOnly, preferDisk)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||||
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexe
|
||||||
}
|
}
|
||||||
|
|
||||||
// stateAtTransaction returns the execution environment of a certain transaction.
|
// stateAtTransaction returns the execution environment of a certain transaction.
|
||||||
func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||||
// Short circuit if it's genesis block.
|
// Short circuit if it's genesis block.
|
||||||
if block.NumberU64() == 0 {
|
if block.NumberU64() == 0 {
|
||||||
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
|
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
|
||||||
|
|
@ -212,7 +212,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
|
||||||
signer := types.MakeSigner(eth.blockchain.Config(), block.Number())
|
signer := types.MakeSigner(eth.blockchain.Config(), block.Number())
|
||||||
for idx, tx := range block.Transactions() {
|
for idx, tx := range block.Transactions() {
|
||||||
// Assemble the transaction call message and return if the requested offset
|
// Assemble the transaction call message and return if the requested offset
|
||||||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
|
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
|
||||||
if idx == txIndex {
|
if idx == txIndex {
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ type Backend interface {
|
||||||
Engine() consensus.Engine
|
Engine() consensus.Engine
|
||||||
ChainDb() ethdb.Database
|
ChainDb() ethdb.Database
|
||||||
StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error)
|
StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error)
|
||||||
StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
|
StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// API is the collection of tracing APIs exposed over the private debugging endpoint.
|
// API is the collection of tracing APIs exposed over the private debugging endpoint.
|
||||||
|
|
@ -293,7 +293,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
|
||||||
)
|
)
|
||||||
// Trace all the transactions contained within
|
// Trace all the transactions contained within
|
||||||
for i, tx := range task.block.Transactions() {
|
for i, tx := range task.block.Transactions() {
|
||||||
msg, _ := tx.AsMessage(signer, task.block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee())
|
||||||
txctx := &Context{
|
txctx := &Context{
|
||||||
BlockHash: task.block.Hash(),
|
BlockHash: task.block.Hash(),
|
||||||
BlockNumber: task.block.Number(),
|
BlockNumber: task.block.Number(),
|
||||||
|
|
@ -554,12 +554,12 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
msg, _ = tx.AsMessage(signer, block.BaseFee())
|
msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext = core.NewEVMTxContext(msg)
|
txContext = core.NewEVMTxContext(msg)
|
||||||
vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
|
vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
|
||||||
)
|
)
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
|
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
|
||||||
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
|
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
|
||||||
// We intentionally don't return the error here: if we do, then the RPC server will not
|
// We intentionally don't return the error here: if we do, then the RPC server will not
|
||||||
// return the roots. Most likely, the caller already knows that a certain transaction fails to
|
// return the roots. Most likely, the caller already knows that a certain transaction fails to
|
||||||
|
|
@ -628,7 +628,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
||||||
)
|
)
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
// Generate the next state snapshot fast without tracing
|
// Generate the next state snapshot fast without tracing
|
||||||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txctx := &Context{
|
txctx := &Context{
|
||||||
BlockHash: blockHash,
|
BlockHash: blockHash,
|
||||||
BlockNumber: block.Number(),
|
BlockNumber: block.Number(),
|
||||||
|
|
@ -671,7 +671,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
|
||||||
defer pend.Done()
|
defer pend.Done()
|
||||||
// Fetch and execute the next transaction trace tasks
|
// Fetch and execute the next transaction trace tasks
|
||||||
for task := range jobs {
|
for task := range jobs {
|
||||||
msg, _ := txs[task.index].AsMessage(signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee())
|
||||||
txctx := &Context{
|
txctx := &Context{
|
||||||
BlockHash: blockHash,
|
BlockHash: blockHash,
|
||||||
BlockNumber: block.Number(),
|
BlockNumber: block.Number(),
|
||||||
|
|
@ -702,10 +702,10 @@ txloop:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the next state snapshot fast without tracing
|
// Generate the next state snapshot fast without tracing
|
||||||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
|
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
|
||||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
|
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
|
||||||
failed = err
|
failed = err
|
||||||
break txloop
|
break txloop
|
||||||
}
|
}
|
||||||
|
|
@ -782,7 +782,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
// Prepare the transaction for un-traced execution
|
// Prepare the transaction for un-traced execution
|
||||||
var (
|
var (
|
||||||
msg, _ = tx.AsMessage(signer, block.BaseFee())
|
msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext = core.NewEVMTxContext(msg)
|
txContext = core.NewEVMTxContext(msg)
|
||||||
vmConf vm.Config
|
vmConf vm.Config
|
||||||
dump *os.File
|
dump *os.File
|
||||||
|
|
@ -813,7 +813,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
||||||
// Execute the transaction and flush any traces to disk
|
// Execute the transaction and flush any traces to disk
|
||||||
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
|
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
|
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
||||||
if writer != nil {
|
if writer != nil {
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
}
|
}
|
||||||
|
|
@ -947,7 +947,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
||||||
// traceTx configures a new tracer according to the provided configuration, and
|
// traceTx configures a new tracer according to the provided configuration, and
|
||||||
// executes the given message in the provided environment. The return value will
|
// executes the given message in the provided environment. The return value will
|
||||||
// be tracer dependent.
|
// be tracer dependent.
|
||||||
func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
|
func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
|
||||||
var (
|
var (
|
||||||
tracer Tracer
|
tracer Tracer
|
||||||
err error
|
err error
|
||||||
|
|
@ -986,7 +986,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex
|
||||||
|
|
||||||
// Call Prepare to clear out the statedb access list
|
// Call Prepare to clear out the statedb access list
|
||||||
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
||||||
if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())); err != nil {
|
if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil {
|
||||||
return nil, fmt.Errorf("tracing failed: %w", err)
|
return nil, fmt.Errorf("tracing failed: %w", err)
|
||||||
}
|
}
|
||||||
return tracer.GetResult()
|
return tracer.GetResult()
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reex
|
||||||
return statedb, release, nil
|
return statedb, release, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) {
|
func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) {
|
||||||
parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return nil, vm.BlockContext{}, nil, nil, errBlockNotFound
|
return nil, vm.BlockContext{}, nil, nil, errBlockNotFound
|
||||||
|
|
@ -171,7 +171,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
|
||||||
// Recompute transactions up to the target index.
|
// Recompute transactions up to the target index.
|
||||||
signer := types.MakeSigner(b.chainConfig, block.Number())
|
signer := types.MakeSigner(b.chainConfig, block.Number())
|
||||||
for idx, tx := range block.Transactions() {
|
for idx, tx := range block.Transactions() {
|
||||||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
|
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
|
||||||
if idx == txIndex {
|
if idx == txIndex {
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
||||||
t.Fatalf("failed to create call tracer: %v", err)
|
t.Fatalf("failed to create call tracer: %v", err)
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
||||||
msg, err := tx.AsMessage(signer, nil)
|
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +220,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
|
||||||
b.Fatalf("failed to parse testcase input: %v", err)
|
b.Fatalf("failed to parse testcase input: %v", err)
|
||||||
}
|
}
|
||||||
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
|
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
|
||||||
msg, err := tx.AsMessage(signer, nil)
|
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed to prepare transaction for tracing: %v", err)
|
b.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -314,7 +314,7 @@ func TestZeroValueToNotExitCall(t *testing.T) {
|
||||||
t.Fatalf("failed to create call tracer: %v", err)
|
t.Fatalf("failed to create call tracer: %v", err)
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
|
||||||
msg, err := tx.AsMessage(signer, nil)
|
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
||||||
|
|
||||||
msg, err := tx.AsMessage(signer, nil)
|
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
|
return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
|
||||||
t.Fatalf("failed to create call tracer: %v", err)
|
t.Fatalf("failed to create call tracer: %v", err)
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
|
||||||
msg, err := tx.AsMessage(signer, nil)
|
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
|
||||||
//EnableReturnData: false,
|
//EnableReturnData: false,
|
||||||
})
|
})
|
||||||
evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer})
|
evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Debug: true, Tracer: tracer})
|
||||||
msg, err := tx.AsMessage(signer, nil)
|
msg, err := core.TransactionToMessage(tx, signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed to prepare transaction for tracing: %v", err)
|
b.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -37,7 +37,6 @@ require (
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/graph-gophers/graphql-go v1.3.0
|
github.com/graph-gophers/graphql-go v1.3.0
|
||||||
github.com/hashicorp/go-bexpr v0.1.10
|
github.com/hashicorp/go-bexpr v0.1.10
|
||||||
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e
|
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3
|
github.com/holiman/bloomfilter/v2 v2.0.3
|
||||||
github.com/holiman/uint256 v1.2.0
|
github.com/holiman/uint256 v1.2.0
|
||||||
github.com/huin/goupnp v1.0.3
|
github.com/huin/goupnp v1.0.3
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -300,8 +300,6 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw=
|
|
||||||
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU=
|
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
||||||
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
|
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
|
||||||
|
|
|
||||||
|
|
@ -1011,7 +1011,7 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
|
||||||
return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
|
return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.Gas())
|
return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.GasLimit)
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
@ -1484,7 +1484,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, nil, err
|
return nil, 0, nil, err
|
||||||
}
|
}
|
||||||
res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
|
res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err)
|
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ type Backend interface {
|
||||||
PendingBlockAndReceipts() (*types.Block, types.Receipts)
|
PendingBlockAndReceipts() (*types.Block, types.Receipts)
|
||||||
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
|
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
|
||||||
GetTd(ctx context.Context, hash common.Hash) *big.Int
|
GetTd(ctx context.Context, hash common.Hash) *big.Int
|
||||||
GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error)
|
GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error)
|
||||||
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
|
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
|
||||||
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
|
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
|
||||||
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
|
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
@ -199,10 +200,10 @@ func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *typ
|
||||||
// ToMessage converts the transaction arguments to the Message type used by the
|
// ToMessage converts the transaction arguments to the Message type used by the
|
||||||
// core evm. This method is used in calls and traces that do not require a real
|
// core evm. This method is used in calls and traces that do not require a real
|
||||||
// live transaction.
|
// live transaction.
|
||||||
func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (types.Message, error) {
|
func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*core.Message, error) {
|
||||||
// Reject invalid combinations of pre- and post-1559 fee styles
|
// Reject invalid combinations of pre- and post-1559 fee styles
|
||||||
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
|
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
|
||||||
return types.Message{}, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
||||||
}
|
}
|
||||||
// Set sender address or use zero address if none specified.
|
// Set sender address or use zero address if none specified.
|
||||||
addr := args.from()
|
addr := args.from()
|
||||||
|
|
@ -263,7 +264,18 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (t
|
||||||
if args.AccessList != nil {
|
if args.AccessList != nil {
|
||||||
accessList = *args.AccessList
|
accessList = *args.AccessList
|
||||||
}
|
}
|
||||||
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, true, false)
|
msg := &core.Message{
|
||||||
|
From: addr,
|
||||||
|
To: args.To,
|
||||||
|
Value: value,
|
||||||
|
GasLimit: gas,
|
||||||
|
GasPrice: gasPrice,
|
||||||
|
GasFeeCap: gasFeeCap,
|
||||||
|
GasTipCap: gasTipCap,
|
||||||
|
Data: data,
|
||||||
|
AccessList: accessList,
|
||||||
|
SkipAccountChecks: true,
|
||||||
|
}
|
||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -305,7 +305,7 @@ func (b *backendMock) GetLogs(ctx context.Context, blockHash common.Hash, number
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil }
|
func (b *backendMock) GetTd(ctx context.Context, hash common.Hash) *big.Int { return nil }
|
||||||
func (b *backendMock) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
func (b *backendMock) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil }
|
func (b *backendMock) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { return nil }
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ func (b *LesApiBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config) (*vm.EVM, func() error, error) {
|
||||||
if vmConfig == nil {
|
if vmConfig == nil {
|
||||||
vmConfig = new(vm.Config)
|
vmConfig = new(vm.Config)
|
||||||
}
|
}
|
||||||
|
|
@ -336,6 +336,6 @@ func (b *LesApiBackend) StateAtBlock(ctx context.Context, block *types.Block, re
|
||||||
return b.eth.stateAtBlock(ctx, block, reexec)
|
return b.eth.stateAtBlock(ctx, block, reexec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||||
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,12 +116,6 @@ func TestOdrContractCallLes2(t *testing.T) { testOdr(t, 2, 2, true, odrContractC
|
||||||
func TestOdrContractCallLes3(t *testing.T) { testOdr(t, 3, 2, true, odrContractCall) }
|
func TestOdrContractCallLes3(t *testing.T) { testOdr(t, 3, 2, true, odrContractCall) }
|
||||||
func TestOdrContractCallLes4(t *testing.T) { testOdr(t, 4, 2, true, odrContractCall) }
|
func TestOdrContractCallLes4(t *testing.T) { testOdr(t, 4, 2, true, odrContractCall) }
|
||||||
|
|
||||||
type callmsg struct {
|
|
||||||
types.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
func (callmsg) CheckNonce() bool { return false }
|
|
||||||
|
|
||||||
func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
|
func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
|
||||||
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
|
||||||
|
|
@ -136,7 +130,17 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
||||||
from := statedb.GetOrNewStateObject(bankAddr)
|
from := statedb.GetOrNewStateObject(bankAddr)
|
||||||
from.SetBalance(math.MaxBig256)
|
from.SetBalance(math.MaxBig256)
|
||||||
|
|
||||||
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true, false)}
|
msg := &core.Message{
|
||||||
|
From: from.Address(),
|
||||||
|
To: &testContractAddr,
|
||||||
|
Value: new(big.Int),
|
||||||
|
GasLimit: 100000,
|
||||||
|
GasPrice: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasFeeCap: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasTipCap: new(big.Int),
|
||||||
|
Data: data,
|
||||||
|
SkipAccountChecks: true,
|
||||||
|
}
|
||||||
|
|
||||||
context := core.NewEVMBlockContext(header, bc, nil)
|
context := core.NewEVMBlockContext(header, bc, nil)
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
|
|
@ -151,7 +155,17 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
||||||
header := lc.GetHeaderByHash(bhash)
|
header := lc.GetHeaderByHash(bhash)
|
||||||
state := light.NewState(ctx, header, lc.Odr())
|
state := light.NewState(ctx, header, lc.Odr())
|
||||||
state.SetBalance(bankAddr, math.MaxBig256)
|
state.SetBalance(bankAddr, math.MaxBig256)
|
||||||
msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true, false)}
|
msg := &core.Message{
|
||||||
|
From: bankAddr,
|
||||||
|
To: &testContractAddr,
|
||||||
|
Value: new(big.Int),
|
||||||
|
GasLimit: 100000,
|
||||||
|
GasPrice: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasFeeCap: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasTipCap: new(big.Int),
|
||||||
|
Data: data,
|
||||||
|
SkipAccountChecks: true,
|
||||||
|
}
|
||||||
context := core.NewEVMBlockContext(header, lc, nil)
|
context := core.NewEVMBlockContext(header, lc, nil)
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{NoBaseFee: true})
|
vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{NoBaseFee: true})
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ func (leth *LightEthereum) stateAtBlock(ctx context.Context, block *types.Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
// stateAtTransaction returns the execution environment of a certain transaction.
|
// stateAtTransaction returns the execution environment of a certain transaction.
|
||||||
func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||||
// Short circuit if it's genesis block.
|
// Short circuit if it's genesis block.
|
||||||
if block.NumberU64() == 0 {
|
if block.NumberU64() == 0 {
|
||||||
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
|
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
|
||||||
|
|
@ -60,7 +60,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.
|
||||||
signer := types.MakeSigner(leth.blockchain.Config(), block.Number())
|
signer := types.MakeSigner(leth.blockchain.Config(), block.Number())
|
||||||
for idx, tx := range block.Transactions() {
|
for idx, tx := range block.Transactions() {
|
||||||
// Assemble the transaction call message and return if the requested offset
|
// Assemble the transaction call message and return if the requested offset
|
||||||
msg, _ := tx.AsMessage(signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil)
|
context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil)
|
||||||
statedb.SetTxContext(tx.Hash(), idx)
|
statedb.SetTxContext(tx.Hash(), idx)
|
||||||
|
|
|
||||||
|
|
@ -174,12 +174,6 @@ func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc
|
||||||
|
|
||||||
func TestOdrContractCallLes2(t *testing.T) { testChainOdr(t, 1, odrContractCall) }
|
func TestOdrContractCallLes2(t *testing.T) { testChainOdr(t, 1, odrContractCall) }
|
||||||
|
|
||||||
type callmsg struct {
|
|
||||||
types.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
func (callmsg) CheckNonce() bool { return false }
|
|
||||||
|
|
||||||
func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
|
func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
|
||||||
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
||||||
config := params.TestChainConfig
|
config := params.TestChainConfig
|
||||||
|
|
@ -205,7 +199,17 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
|
||||||
|
|
||||||
// Perform read-only call.
|
// Perform read-only call.
|
||||||
st.SetBalance(testBankAddress, math.MaxBig256)
|
st.SetBalance(testBankAddress, math.MaxBig256)
|
||||||
msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true, false)}
|
msg := &core.Message{
|
||||||
|
From: testBankAddress,
|
||||||
|
To: &testContractAddr,
|
||||||
|
Value: new(big.Int),
|
||||||
|
GasLimit: 1000000,
|
||||||
|
GasPrice: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasFeeCap: big.NewInt(params.InitialBaseFee),
|
||||||
|
GasTipCap: new(big.Int),
|
||||||
|
Data: data,
|
||||||
|
SkipAccountChecks: true,
|
||||||
|
}
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
context := core.NewEVMBlockContext(header, chain, nil)
|
context := core.NewEVMBlockContext(header, chain, nil)
|
||||||
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true})
|
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true})
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,5 @@ compile_fuzzer tests/fuzzers/snap FuzzSRange fuzz_storage_range
|
||||||
compile_fuzzer tests/fuzzers/snap FuzzByteCodes fuzz_byte_codes
|
compile_fuzzer tests/fuzzers/snap FuzzByteCodes fuzz_byte_codes
|
||||||
compile_fuzzer tests/fuzzers/snap FuzzTrieNodes fuzz_trie_nodes
|
compile_fuzzer tests/fuzzers/snap FuzzTrieNodes fuzz_trie_nodes
|
||||||
|
|
||||||
compile_fuzzer tests/fuzzers/modexp Fuzz fuzzModexp
|
|
||||||
|
|
||||||
#TODO: move this to tests/fuzzers, if possible
|
#TODO: move this to tests/fuzzers, if possible
|
||||||
compile_fuzzer crypto/blake2b Fuzz fuzzBlake2b
|
compile_fuzzer crypto/blake2b Fuzz fuzzBlake2b
|
||||||
|
|
|
||||||
|
|
@ -1057,7 +1057,7 @@ func (srv *Server) runPeer(p *Peer) {
|
||||||
// Broadcast peer drop to external subscribers. This needs to be
|
// Broadcast peer drop to external subscribers. This needs to be
|
||||||
// after the send to delpeer so subscribers have a consistent view of
|
// after the send to delpeer so subscribers have a consistent view of
|
||||||
// the peer set (i.e. Server.Peers() doesn't include the peer when the
|
// the peer set (i.e. Server.Peers() doesn't include the peer when the
|
||||||
// event is received.
|
// event is received).
|
||||||
srv.peerFeed.Send(&PeerEvent{
|
srv.peerFeed.Send(&PeerEvent{
|
||||||
Type: PeerEventTypeDrop,
|
Type: PeerEventTypeDrop,
|
||||||
Peer: p.ID(),
|
Peer: p.ID(),
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,6 @@ var MainnetBootnodes = []string{
|
||||||
// Ethereum Foundation Go Bootnodes
|
// Ethereum Foundation Go Bootnodes
|
||||||
"enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303", // bootnode-aws-ap-southeast-1-001
|
"enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303", // bootnode-aws-ap-southeast-1-001
|
||||||
"enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303", // bootnode-aws-us-east-1-001
|
"enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303", // bootnode-aws-us-east-1-001
|
||||||
"enode://8499da03c47d637b20eee24eec3c356c9a2e6148d6fe25ca195c7949ab8ec2c03e3556126b0d7ed644675e78c4318b08691b7b57de10e5f0d40d05b09238fa0a@52.187.207.27:30303", // bootnode-azure-australiaeast-001
|
|
||||||
"enode://103858bdb88756c71f15e9b5e09b56dc1be52f0a5021d46301dbbfb7e130029cc9d0d6f73f693bc29b665770fff7da4d34f3c6379fe12721b5d7a0bcb5ca1fc1@191.234.162.198:30303", // bootnode-azure-brazilsouth-001
|
|
||||||
"enode://715171f50508aba88aecd1250af392a45a330af91d7b90701c436b618c86aaa1589c9184561907bebbb56439b8f8787bc01f49a7c77276c58c1b09822d75e8e8@52.231.165.108:30303", // bootnode-azure-koreasouth-001
|
|
||||||
"enode://5d6d7cd20d6da4bb83a1d28cadb5d409b64edf314c0335df658c1a54e32c7c4a7ab7823d57c39b6a757556e68ff1df17c748b698544a55cb488b52479a92b60f@104.42.217.25:30303", // bootnode-azure-westus-001
|
|
||||||
"enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303", // bootnode-hetzner-hel
|
"enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303", // bootnode-hetzner-hel
|
||||||
"enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303", // bootnode-hetzner-fsn
|
"enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303", // bootnode-hetzner-fsn
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ var (
|
||||||
const (
|
const (
|
||||||
VersionMajor = 1 // Major version component of the current release
|
VersionMajor = 1 // Major version component of the current release
|
||||||
VersionMinor = 11 // Minor version component of the current release
|
VersionMinor = 11 // Minor version component of the current release
|
||||||
VersionPatch = 3 // Patch version component of the current release
|
VersionPatch = 4 // Patch version component of the current release
|
||||||
VersionMeta = "stable" // Version metadata to append to the version string
|
VersionMeta = "stable" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -742,113 +742,31 @@ func isPrimitiveTypeValid(primitiveType string) bool {
|
||||||
primitiveType == "bool" ||
|
primitiveType == "bool" ||
|
||||||
primitiveType == "bool[]" ||
|
primitiveType == "bool[]" ||
|
||||||
primitiveType == "string" ||
|
primitiveType == "string" ||
|
||||||
primitiveType == "string[]" {
|
primitiveType == "string[]" ||
|
||||||
return true
|
primitiveType == "bytes" ||
|
||||||
}
|
|
||||||
if primitiveType == "bytes" ||
|
|
||||||
primitiveType == "bytes[]" ||
|
primitiveType == "bytes[]" ||
|
||||||
primitiveType == "bytes1" ||
|
primitiveType == "int" ||
|
||||||
primitiveType == "bytes1[]" ||
|
|
||||||
primitiveType == "bytes2" ||
|
|
||||||
primitiveType == "bytes2[]" ||
|
|
||||||
primitiveType == "bytes3" ||
|
|
||||||
primitiveType == "bytes3[]" ||
|
|
||||||
primitiveType == "bytes4" ||
|
|
||||||
primitiveType == "bytes4[]" ||
|
|
||||||
primitiveType == "bytes5" ||
|
|
||||||
primitiveType == "bytes5[]" ||
|
|
||||||
primitiveType == "bytes6" ||
|
|
||||||
primitiveType == "bytes6[]" ||
|
|
||||||
primitiveType == "bytes7" ||
|
|
||||||
primitiveType == "bytes7[]" ||
|
|
||||||
primitiveType == "bytes8" ||
|
|
||||||
primitiveType == "bytes8[]" ||
|
|
||||||
primitiveType == "bytes9" ||
|
|
||||||
primitiveType == "bytes9[]" ||
|
|
||||||
primitiveType == "bytes10" ||
|
|
||||||
primitiveType == "bytes10[]" ||
|
|
||||||
primitiveType == "bytes11" ||
|
|
||||||
primitiveType == "bytes11[]" ||
|
|
||||||
primitiveType == "bytes12" ||
|
|
||||||
primitiveType == "bytes12[]" ||
|
|
||||||
primitiveType == "bytes13" ||
|
|
||||||
primitiveType == "bytes13[]" ||
|
|
||||||
primitiveType == "bytes14" ||
|
|
||||||
primitiveType == "bytes14[]" ||
|
|
||||||
primitiveType == "bytes15" ||
|
|
||||||
primitiveType == "bytes15[]" ||
|
|
||||||
primitiveType == "bytes16" ||
|
|
||||||
primitiveType == "bytes16[]" ||
|
|
||||||
primitiveType == "bytes17" ||
|
|
||||||
primitiveType == "bytes17[]" ||
|
|
||||||
primitiveType == "bytes18" ||
|
|
||||||
primitiveType == "bytes18[]" ||
|
|
||||||
primitiveType == "bytes19" ||
|
|
||||||
primitiveType == "bytes19[]" ||
|
|
||||||
primitiveType == "bytes20" ||
|
|
||||||
primitiveType == "bytes20[]" ||
|
|
||||||
primitiveType == "bytes21" ||
|
|
||||||
primitiveType == "bytes21[]" ||
|
|
||||||
primitiveType == "bytes22" ||
|
|
||||||
primitiveType == "bytes22[]" ||
|
|
||||||
primitiveType == "bytes23" ||
|
|
||||||
primitiveType == "bytes23[]" ||
|
|
||||||
primitiveType == "bytes24" ||
|
|
||||||
primitiveType == "bytes24[]" ||
|
|
||||||
primitiveType == "bytes25" ||
|
|
||||||
primitiveType == "bytes25[]" ||
|
|
||||||
primitiveType == "bytes26" ||
|
|
||||||
primitiveType == "bytes26[]" ||
|
|
||||||
primitiveType == "bytes27" ||
|
|
||||||
primitiveType == "bytes27[]" ||
|
|
||||||
primitiveType == "bytes28" ||
|
|
||||||
primitiveType == "bytes28[]" ||
|
|
||||||
primitiveType == "bytes29" ||
|
|
||||||
primitiveType == "bytes29[]" ||
|
|
||||||
primitiveType == "bytes30" ||
|
|
||||||
primitiveType == "bytes30[]" ||
|
|
||||||
primitiveType == "bytes31" ||
|
|
||||||
primitiveType == "bytes31[]" ||
|
|
||||||
primitiveType == "bytes32" ||
|
|
||||||
primitiveType == "bytes32[]" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if primitiveType == "int" ||
|
|
||||||
primitiveType == "int[]" ||
|
primitiveType == "int[]" ||
|
||||||
primitiveType == "int8" ||
|
primitiveType == "uint" ||
|
||||||
primitiveType == "int8[]" ||
|
primitiveType == "uint[]" {
|
||||||
primitiveType == "int16" ||
|
|
||||||
primitiveType == "int16[]" ||
|
|
||||||
primitiveType == "int32" ||
|
|
||||||
primitiveType == "int32[]" ||
|
|
||||||
primitiveType == "int64" ||
|
|
||||||
primitiveType == "int64[]" ||
|
|
||||||
primitiveType == "int96" ||
|
|
||||||
primitiveType == "int96[]" ||
|
|
||||||
primitiveType == "int128" ||
|
|
||||||
primitiveType == "int128[]" ||
|
|
||||||
primitiveType == "int256" ||
|
|
||||||
primitiveType == "int256[]" {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if primitiveType == "uint" ||
|
// For 'bytesN', 'bytesN[]', we allow N from 1 to 32
|
||||||
primitiveType == "uint[]" ||
|
for n := 1; n <= 32; n++ {
|
||||||
primitiveType == "uint8" ||
|
// e.g. 'bytes28' or 'bytes28[]'
|
||||||
primitiveType == "uint8[]" ||
|
if primitiveType == fmt.Sprintf("bytes%d", n) || primitiveType == fmt.Sprintf("bytes%d[]", n) {
|
||||||
primitiveType == "uint16" ||
|
|
||||||
primitiveType == "uint16[]" ||
|
|
||||||
primitiveType == "uint32" ||
|
|
||||||
primitiveType == "uint32[]" ||
|
|
||||||
primitiveType == "uint64" ||
|
|
||||||
primitiveType == "uint64[]" ||
|
|
||||||
primitiveType == "uint96" ||
|
|
||||||
primitiveType == "uint96[]" ||
|
|
||||||
primitiveType == "uint128" ||
|
|
||||||
primitiveType == "uint128[]" ||
|
|
||||||
primitiveType == "uint256" ||
|
|
||||||
primitiveType == "uint256[]" {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// For 'intN','intN[]' and 'uintN','uintN[]' we allow N in increments of 8, from 8 up to 256
|
||||||
|
for n := 8; n <= 256; n += 8 {
|
||||||
|
if primitiveType == fmt.Sprintf("int%d", n) || primitiveType == fmt.Sprintf("int%d[]", n) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if primitiveType == fmt.Sprintf("uint%d", n) || primitiveType == fmt.Sprintf("uint%d[]", n) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2020 The go-ethereum Authors
|
// Copyright 2023 The go-ethereum Authors
|
||||||
// This file is part of the go-ethereum library.
|
// This file is part of the go-ethereum library.
|
||||||
//
|
//
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -14,27 +14,27 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// 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/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package main
|
package apitypes
|
||||||
|
|
||||||
import (
|
import "testing"
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/tests/fuzzers/modexp"
|
func TestIsPrimitive(t *testing.T) {
|
||||||
)
|
// Expected positives
|
||||||
|
for i, tc := range []string{
|
||||||
func main() {
|
"int24", "int24[]", "uint88", "uint88[]", "uint", "uint[]", "int256", "int256[]",
|
||||||
if len(os.Args) != 2 {
|
"uint96", "uint96[]", "int96", "int96[]", "bytes17[]", "bytes17",
|
||||||
fmt.Fprintf(os.Stderr, "Usage: debug <file>\n")
|
} {
|
||||||
fmt.Fprintf(os.Stderr, "Example\n")
|
if !isPrimitiveTypeValid(tc) {
|
||||||
fmt.Fprintf(os.Stderr, " $ debug ../crashers/4bbef6857c733a87ecf6fd8b9e7238f65eb9862a\n")
|
t.Errorf("test %d: expected '%v' to be a valid primitive", i, tc)
|
||||||
os.Exit(1)
|
}
|
||||||
|
}
|
||||||
|
// Expected negatives
|
||||||
|
for i, tc := range []string{
|
||||||
|
"int257", "int257[]", "uint88 ", "uint88 []", "uint257", "uint-1[]",
|
||||||
|
"uint0", "uint0[]", "int95", "int95[]", "uint1", "uint1[]", "bytes33[]", "bytess",
|
||||||
|
} {
|
||||||
|
if isPrimitiveTypeValid(tc) {
|
||||||
|
t.Errorf("test %d: expected '%v' to not be a valid primitive", i, tc)
|
||||||
}
|
}
|
||||||
crasher := os.Args[1]
|
|
||||||
data, err := os.ReadFile(crasher)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "error loading crasher %v: %v", crasher, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
modexp.Fuzz(data)
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
// Copyright 2022 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 modexp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
|
||||||
big2 "github.com/holiman/big"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Fuzz is the fuzzing entry-point.
|
|
||||||
// The function must return
|
|
||||||
//
|
|
||||||
// - 1 if the fuzzer should increase priority of the
|
|
||||||
// given input during subsequent fuzzing (for example, the input is lexically
|
|
||||||
// correct and was parsed successfully);
|
|
||||||
// - -1 if the input must not be added to corpus even if gives new coverage; and
|
|
||||||
// - 0 otherwise
|
|
||||||
//
|
|
||||||
// other values are reserved for future use.
|
|
||||||
func Fuzz(input []byte) int {
|
|
||||||
if len(input) <= 96 {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
// Abort on too expensive inputs
|
|
||||||
precomp := vm.PrecompiledContractsBerlin[common.BytesToAddress([]byte{5})]
|
|
||||||
if gas := precomp.RequiredGas(input); gas > 40_000_000 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64()
|
|
||||||
expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64()
|
|
||||||
modLen = new(big.Int).SetBytes(getData(input, 64, 32)).Uint64()
|
|
||||||
)
|
|
||||||
// Handle a special case when both the base and mod length is zero
|
|
||||||
if baseLen == 0 && modLen == 0 {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
input = input[96:]
|
|
||||||
// Retrieve the operands and execute the exponentiation
|
|
||||||
var (
|
|
||||||
base = new(big.Int).SetBytes(getData(input, 0, baseLen))
|
|
||||||
exp = new(big.Int).SetBytes(getData(input, baseLen, expLen))
|
|
||||||
mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen))
|
|
||||||
base2 = new(big2.Int).SetBytes(getData(input, 0, baseLen))
|
|
||||||
exp2 = new(big2.Int).SetBytes(getData(input, baseLen, expLen))
|
|
||||||
mod2 = new(big2.Int).SetBytes(getData(input, baseLen+expLen, modLen))
|
|
||||||
)
|
|
||||||
if mod.BitLen() == 0 {
|
|
||||||
// Modulo 0 is undefined, return zero
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
var a = new(big2.Int).Exp(base2, exp2, mod2).String()
|
|
||||||
var b = new(big.Int).Exp(base, exp, mod).String()
|
|
||||||
if a != b {
|
|
||||||
panic(fmt.Sprintf("Inequality %#x ^ %#x mod %#x \n have %s\n want %s", base, exp, mod, a, b))
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// getData returns a slice from the data based on the start and size and pads
|
|
||||||
// up to size with zero's. This function is overflow safe.
|
|
||||||
func getData(data []byte, start uint64, size uint64) []byte {
|
|
||||||
length := uint64(len(data))
|
|
||||||
if start > length {
|
|
||||||
start = length
|
|
||||||
}
|
|
||||||
end := start + size
|
|
||||||
if end > length {
|
|
||||||
end = length
|
|
||||||
}
|
|
||||||
return common.RightPadBytes(data[start:end], int(size))
|
|
||||||
}
|
|
||||||
|
|
@ -228,7 +228,7 @@ func runBenchmark(b *testing.B, t *StateTest) {
|
||||||
evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
|
evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
|
||||||
|
|
||||||
// Create "contract" for sender to cache code analysis.
|
// Create "contract" for sender to cache code analysis.
|
||||||
sender := vm.NewContract(vm.AccountRef(msg.From()), vm.AccountRef(msg.From()),
|
sender := vm.NewContract(vm.AccountRef(msg.From), vm.AccountRef(msg.From),
|
||||||
nil, 0)
|
nil, 0)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -239,12 +239,12 @@ func runBenchmark(b *testing.B, t *StateTest) {
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for n := 0; n < b.N; n++ {
|
for n := 0; n < b.N; n++ {
|
||||||
snapshot := statedb.Snapshot()
|
snapshot := statedb.Snapshot()
|
||||||
statedb.Prepare(rules, msg.From(), context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
|
statedb.Prepare(rules, msg.From, context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList)
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
// Execute the message.
|
// Execute the message.
|
||||||
_, leftOverGas, err := evm.Call(sender, *msg.To(), msg.Data(), msg.Gas(), msg.Value())
|
_, leftOverGas, err := evm.Call(sender, *msg.To, msg.Data, msg.GasLimit, msg.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Error(err)
|
b.Error(err)
|
||||||
return
|
return
|
||||||
|
|
@ -253,7 +253,7 @@ func runBenchmark(b *testing.B, t *StateTest) {
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
elapsed += uint64(time.Since(start))
|
elapsed += uint64(time.Since(start))
|
||||||
refund += statedb.GetRefund()
|
refund += statedb.GetRefund()
|
||||||
gasUsed += msg.Gas() - leftOverGas
|
gasUsed += msg.GasLimit - leftOverGas
|
||||||
|
|
||||||
statedb.RevertToSnapshot(snapshot)
|
statedb.RevertToSnapshot(snapshot)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -329,7 +329,7 @@ func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis {
|
||||||
return genesis
|
return genesis
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (core.Message, error) {
|
func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Message, error) {
|
||||||
// Derive sender from private key if present.
|
// Derive sender from private key if present.
|
||||||
var from common.Address
|
var from common.Address
|
||||||
if len(tx.PrivateKey) > 0 {
|
if len(tx.PrivateKey) > 0 {
|
||||||
|
|
@ -397,8 +397,18 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (core.Messa
|
||||||
return nil, fmt.Errorf("no gas price provided")
|
return nil, fmt.Errorf("no gas price provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, gasPrice,
|
msg := &core.Message{
|
||||||
tx.MaxFeePerGas, tx.MaxPriorityFeePerGas, data, accessList, false, false)
|
From: from,
|
||||||
|
To: to,
|
||||||
|
Nonce: tx.Nonce,
|
||||||
|
Value: value,
|
||||||
|
GasLimit: gasLimit,
|
||||||
|
GasPrice: gasPrice,
|
||||||
|
GasFeeCap: tx.MaxFeePerGas,
|
||||||
|
GasTipCap: tx.MaxPriorityFeePerGas,
|
||||||
|
Data: data,
|
||||||
|
AccessList: accessList,
|
||||||
|
}
|
||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue