forked from XinFinOrg/XDPoSChain
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
core: add new eip-1559 tx constraints (ethereum#22970)
- Loading branch information
Showing
6 changed files
with
368 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,290 @@ | ||
// Copyright 2020 The go-ethereum Authors | ||
// This file is part of the go-ethereum library. | ||
// | ||
// The go-ethereum library is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU Lesser General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// The go-ethereum library is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU Lesser General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU Lesser General Public License | ||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
package core | ||
|
||
import ( | ||
"math/big" | ||
"testing" | ||
|
||
"github.com/XinFinOrg/XDPoSChain/common" | ||
"github.com/XinFinOrg/XDPoSChain/consensus" | ||
"github.com/XinFinOrg/XDPoSChain/consensus/ethash" | ||
"github.com/XinFinOrg/XDPoSChain/core/rawdb" | ||
"github.com/XinFinOrg/XDPoSChain/core/types" | ||
"github.com/XinFinOrg/XDPoSChain/core/vm" | ||
"github.com/XinFinOrg/XDPoSChain/crypto" | ||
"github.com/XinFinOrg/XDPoSChain/params" | ||
"golang.org/x/crypto/sha3" | ||
) | ||
|
||
// TestStateProcessorErrors tests the output from the 'core' errors | ||
// as defined in core/error.go. These errors are generated when the | ||
// blockchain imports bad blocks, meaning blocks which have valid headers but | ||
// contain invalid transactions | ||
func TestStateProcessorErrors(t *testing.T) { | ||
var ( | ||
config = ¶ms.ChainConfig{ | ||
ChainId: big.NewInt(1), | ||
HomesteadBlock: big.NewInt(0), | ||
EIP150Block: big.NewInt(0), | ||
EIP155Block: big.NewInt(0), | ||
EIP158Block: big.NewInt(0), | ||
ByzantiumBlock: big.NewInt(0), | ||
ConstantinopleBlock: big.NewInt(0), | ||
PetersburgBlock: big.NewInt(0), | ||
IstanbulBlock: big.NewInt(0), | ||
BerlinBlock: big.NewInt(0), | ||
LondonBlock: big.NewInt(0), | ||
Eip1559Block: big.NewInt(0), | ||
Ethash: new(params.EthashConfig), | ||
} | ||
signer = types.LatestSigner(config) | ||
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") | ||
) | ||
var makeTx = func(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction { | ||
tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data) | ||
signedTx, err := types.SignTx(tx, signer, testKey) | ||
if err != nil { | ||
t.Fatalf("fail to sign tx: %v, err: %v", tx, err) | ||
} | ||
return signedTx | ||
} | ||
var mkDynamicTx = func(nonce uint64, to common.Address, gasLimit uint64, tip, feeCap *big.Int) *types.Transaction { | ||
tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{ | ||
Nonce: nonce, | ||
Tip: tip, | ||
FeeCap: feeCap, | ||
Gas: gasLimit, | ||
To: &to, | ||
Value: big.NewInt(0), | ||
}), signer, testKey) | ||
return tx | ||
} | ||
{ // Tests against a 'recent' chain definition | ||
var ( | ||
db = rawdb.NewMemoryDatabase() | ||
gspec = &Genesis{ | ||
Config: config, | ||
Alloc: GenesisAlloc{ | ||
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ | ||
Balance: big.NewInt(1000000000000000000), // 1 ether | ||
Nonce: 0, | ||
}, | ||
}, | ||
} | ||
genesis = gspec.MustCommit(db) | ||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) | ||
) | ||
defer blockchain.Stop() | ||
bigNumber := new(big.Int).SetBytes(common.FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")) | ||
tooBigNumber := new(big.Int).Set(bigNumber) | ||
tooBigNumber.Add(tooBigNumber, common.Big1) | ||
for i, tt := range []struct { | ||
txs []*types.Transaction | ||
want string | ||
}{ | ||
{ // ErrNonceTooLow | ||
txs: []*types.Transaction{ | ||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil), | ||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil), | ||
}, | ||
want: "nonce too low: address xdc71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1", | ||
}, | ||
{ // ErrNonceTooHigh | ||
txs: []*types.Transaction{ | ||
makeTx(100, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(875000000), nil), | ||
}, | ||
want: "nonce too high: address xdc71562b71999873DB5b286dF957af199Ec94617F7, tx: 100 state: 0", | ||
}, | ||
{ // ErrGasLimitReached | ||
txs: []*types.Transaction{ | ||
makeTx(0, common.Address{}, big.NewInt(0), 21000000, big.NewInt(875000000), nil), | ||
}, | ||
want: "gas limit reached", | ||
}, | ||
{ // ErrInsufficientFundsForTransfer | ||
txs: []*types.Transaction{ | ||
makeTx(0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(875000000), nil), | ||
}, | ||
want: "insufficient funds for transfer: address xdc71562b71999873DB5b286dF957af199Ec94617F7", | ||
}, | ||
{ // ErrInsufficientFunds | ||
txs: []*types.Transaction{ | ||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(900000000000000000), nil), | ||
}, | ||
want: "insufficient funds for gas * price + value: address xdc71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 18900000000000000000000", | ||
}, | ||
// ErrGasUintOverflow | ||
// One missing 'core' error is ErrGasUintOverflow: "gas uint64 overflow", | ||
// In order to trigger that one, we'd have to allocate a _huge_ chunk of data, such that the | ||
// multiplication len(data) +gas_per_byte overflows uint64. Not testable at the moment | ||
{ // ErrIntrinsicGas | ||
txs: []*types.Transaction{ | ||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(875000000), nil), | ||
}, | ||
want: "intrinsic gas too low: have 20000, want 21000", | ||
}, | ||
{ // ErrGasLimitReached | ||
txs: []*types.Transaction{ | ||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas*1000, big.NewInt(875000000), nil), | ||
}, | ||
want: "gas limit reached", | ||
}, | ||
{ // ErrFeeCapTooLow | ||
txs: []*types.Transaction{ | ||
mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(0), big.NewInt(0)), | ||
}, | ||
want: "fee cap less than block base fee: address xdc71562b71999873DB5b286dF957af199Ec94617F7, feeCap: 0 baseFee: 875000000", | ||
}, | ||
{ // ErrTipVeryHigh | ||
txs: []*types.Transaction{ | ||
mkDynamicTx(0, common.Address{}, params.TxGas, tooBigNumber, big.NewInt(1)), | ||
}, | ||
want: "tip higher than 2^256-1: address xdc71562b71999873DB5b286dF957af199Ec94617F7, tip bit length: 257", | ||
}, | ||
{ // ErrFeeCapVeryHigh | ||
txs: []*types.Transaction{ | ||
mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(1), tooBigNumber), | ||
}, | ||
want: "fee cap higher than 2^256-1: address xdc71562b71999873DB5b286dF957af199Ec94617F7, feeCap bit length: 257", | ||
}, | ||
{ // ErrTipAboveFeeCap | ||
txs: []*types.Transaction{ | ||
mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(2), big.NewInt(1)), | ||
}, | ||
want: "tip higher than fee cap: address xdc71562b71999873DB5b286dF957af199Ec94617F7, tip: 1, feeCap: 2", | ||
}, | ||
{ // ErrInsufficientFunds | ||
// Available balance: 1000000000000000000 | ||
// Effective cost: 18375000021000 | ||
// FeeCap * gas: 1050000000000000000 | ||
// This test is designed to have the effective cost be covered by the balance, but | ||
// the extended requirement on FeeCap*gas < balance to fail | ||
txs: []*types.Transaction{ | ||
mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(1), big.NewInt(50000000000000)), | ||
}, | ||
want: "insufficient funds for gas * price + value: address xdc71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 1050000000000000000", | ||
}, | ||
{ // Another ErrInsufficientFunds, this one to ensure that feecap/tip of max u256 is allowed | ||
txs: []*types.Transaction{ | ||
mkDynamicTx(0, common.Address{}, params.TxGas, bigNumber, bigNumber), | ||
}, | ||
want: "insufficient funds for gas * price + value: address xdc71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 2431633873983640103894990685182446064918669677978451844828609264166175722438635000", | ||
}, | ||
}[8:] { | ||
block := GenerateBadBlock(t, genesis, ethash.NewFaker(), tt.txs, gspec.Config) | ||
_, err := blockchain.InsertChain(types.Blocks{block}) | ||
if err == nil { | ||
t.Fatal("block imported without errors") | ||
} | ||
if have, want := err.Error(), tt.want; have != want { | ||
t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) | ||
} | ||
} | ||
} | ||
|
||
// One final error is ErrTxTypeNotSupported. For this, we need an older chain | ||
{ | ||
var ( | ||
db = rawdb.NewMemoryDatabase() | ||
gspec = &Genesis{ | ||
Config: ¶ms.ChainConfig{ | ||
ChainId: big.NewInt(1), | ||
HomesteadBlock: big.NewInt(0), | ||
EIP150Block: big.NewInt(0), | ||
EIP155Block: big.NewInt(0), | ||
EIP158Block: big.NewInt(0), | ||
ByzantiumBlock: big.NewInt(0), | ||
ConstantinopleBlock: big.NewInt(0), | ||
PetersburgBlock: big.NewInt(0), | ||
IstanbulBlock: big.NewInt(0), | ||
}, | ||
Alloc: GenesisAlloc{ | ||
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{ | ||
Balance: big.NewInt(1000000000000000000), // 1 ether | ||
Nonce: 0, | ||
}, | ||
}, | ||
} | ||
genesis = gspec.MustCommit(db) | ||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) | ||
) | ||
defer blockchain.Stop() | ||
for i, tt := range []struct { | ||
txs []*types.Transaction | ||
want string | ||
}{ | ||
{ // ErrTxTypeNotSupported | ||
txs: []*types.Transaction{ | ||
mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)), | ||
}, | ||
want: "transaction type not supported", | ||
}, | ||
} { | ||
block := GenerateBadBlock(t, genesis, ethash.NewFaker(), tt.txs, gspec.Config) | ||
_, err := blockchain.InsertChain(types.Blocks{block}) | ||
if err == nil { | ||
t.Fatal("block imported without errors") | ||
} | ||
if have, want := err.Error(), tt.want; have != want { | ||
t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want) | ||
} | ||
} | ||
} | ||
} | ||
|
||
// GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be | ||
// valid, and no proper post-state can be made. But from the perspective of the blockchain, the block is sufficiently | ||
// valid to be considered for import: | ||
// - valid pow (fake), ancestry, difficulty, gaslimit etc | ||
func GenerateBadBlock(t *testing.T, parent *types.Block, engine consensus.Engine, txs types.Transactions, config *params.ChainConfig) *types.Block { | ||
header := &types.Header{ | ||
ParentHash: parent.Hash(), | ||
Coinbase: parent.Coinbase(), | ||
Difficulty: engine.CalcDifficulty(&fakeChainReader{config}, parent.Time().Uint64()+10, &types.Header{ | ||
Number: parent.Number(), | ||
Time: parent.Time(), | ||
Difficulty: parent.Difficulty(), | ||
UncleHash: parent.UncleHash(), | ||
}), | ||
GasLimit: parent.GasLimit(), | ||
Number: new(big.Int).Add(parent.Number(), common.Big1), | ||
Time: new(big.Int).SetUint64(parent.Time().Uint64() + 10), | ||
UncleHash: types.EmptyUncleHash, | ||
} | ||
if config.IsEIP1559(header.Number) { | ||
header.BaseFee = common.BaseFee | ||
} | ||
var receipts []*types.Receipt | ||
// The post-state result doesn't need to be correct (this is a bad block), but we do need something there | ||
// Preferably something unique. So let's use a combo of blocknum + txhash | ||
hasher := sha3.NewLegacyKeccak256() | ||
hasher.Write(header.Number.Bytes()) | ||
var cumulativeGas uint64 | ||
for _, tx := range txs { | ||
txh := tx.Hash() | ||
hasher.Write(txh[:]) | ||
receipt := types.NewReceipt(nil, false, cumulativeGas+tx.Gas()) | ||
receipt.TxHash = tx.Hash() | ||
receipt.GasUsed = tx.Gas() | ||
receipts = append(receipts, receipt) | ||
cumulativeGas += tx.Gas() | ||
} | ||
header.Root = common.BytesToHash(hasher.Sum(nil)) | ||
// Assemble and return the final block for sealing | ||
return types.NewBlock(header, txs, nil, receipts) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.