mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 13:21:37 +00:00
parent
b08622248c
commit
142b1155d8
35 changed files with 1372 additions and 106 deletions
|
|
@ -30,9 +30,9 @@ var DevnetConstant = constant{
|
|||
eip1559Block: big.NewInt(32400),
|
||||
cancunBlock: big.NewInt(43200),
|
||||
pragueBlock: big.NewInt(math.MaxInt64),
|
||||
tipUpgradeReward: big.NewInt(9999999999),
|
||||
tipUpgradePenalty: big.NewInt(9999999999),
|
||||
tipEpochHalving: big.NewInt(9999999999),
|
||||
tipUpgradeReward: big.NewInt(math.MaxInt64),
|
||||
tipUpgradePenalty: big.NewInt(math.MaxInt64),
|
||||
tipEpochHalving: big.NewInt(math.MaxInt64),
|
||||
|
||||
trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"),
|
||||
xdcxListingSMC: HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"),
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ var localConstant = constant{
|
|||
eip1559Block: big.NewInt(0),
|
||||
cancunBlock: big.NewInt(0),
|
||||
pragueBlock: big.NewInt(math.MaxInt64),
|
||||
tipUpgradeReward: big.NewInt(999999999),
|
||||
tipUpgradePenalty: big.NewInt(999999999),
|
||||
tipEpochHalving: big.NewInt(999999999),
|
||||
tipUpgradeReward: big.NewInt(math.MaxInt64),
|
||||
tipUpgradePenalty: big.NewInt(math.MaxInt64),
|
||||
tipEpochHalving: big.NewInt(math.MaxInt64),
|
||||
|
||||
trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"),
|
||||
xdcxListingSMC: HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"),
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@ var MainnetConstant = constant{
|
|||
TIPV2SwitchBlock: big.NewInt(80370000), // Target 2nd Oct 2024
|
||||
tipXDCXMinerDisable: big.NewInt(80370000), // Target 2nd Oct 2024
|
||||
tipXDCXReceiverDisable: big.NewInt(80370900), // Target 2nd Oct 2024, safer to release after disable miner
|
||||
eip1559Block: big.NewInt(9999999999),
|
||||
cancunBlock: big.NewInt(9999999999),
|
||||
eip1559Block: big.NewInt(math.MaxInt64),
|
||||
cancunBlock: big.NewInt(math.MaxInt64),
|
||||
pragueBlock: big.NewInt(math.MaxInt64),
|
||||
tipUpgradeReward: big.NewInt(9999999999),
|
||||
tipUpgradePenalty: big.NewInt(9999999999),
|
||||
tipEpochHalving: big.NewInt(9999999999),
|
||||
tipUpgradeReward: big.NewInt(math.MaxInt64),
|
||||
tipUpgradePenalty: big.NewInt(math.MaxInt64),
|
||||
tipEpochHalving: big.NewInt(math.MaxInt64),
|
||||
|
||||
trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"),
|
||||
xdcxListingSMC: HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"),
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ var TestnetConstant = constant{
|
|||
eip1559Block: big.NewInt(71550000), // Target 14th Feb 2025
|
||||
cancunBlock: big.NewInt(71551800),
|
||||
pragueBlock: big.NewInt(math.MaxInt64),
|
||||
tipUpgradeReward: big.NewInt(9999999999),
|
||||
tipUpgradePenalty: big.NewInt(9999999999),
|
||||
tipEpochHalving: big.NewInt(9999999999),
|
||||
tipUpgradeReward: big.NewInt(math.MaxInt64),
|
||||
tipUpgradePenalty: big.NewInt(math.MaxInt64),
|
||||
tipEpochHalving: big.NewInt(math.MaxInt64),
|
||||
|
||||
trc21IssuerSMC: HexToAddress("0x0E2C88753131CE01c7551B726b28BFD04e44003F"),
|
||||
xdcxListingSMC: HexToAddress("0x14B2Bf043b9c31827A472CE4F94294fE9a6277e0"),
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
|
|||
return func(i int, gen *BlockGen) {
|
||||
toaddr := common.Address{}
|
||||
data := make([]byte, nbytes)
|
||||
gas, _ := IntrinsicGas(data, nil, false, false, false)
|
||||
gas, _ := IntrinsicGas(data, nil, nil, false, false, false)
|
||||
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey)
|
||||
gen.AddTx(tx)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,9 +99,25 @@ var (
|
|||
// ErrSenderNoEOA is returned if the sender of a transaction is a contract.
|
||||
ErrSenderNoEOA = errors.New("sender not an eoa")
|
||||
|
||||
ErrNotXDPoS = errors.New("XDPoS not found in config")
|
||||
|
||||
ErrNotFoundM1 = errors.New("list M1 not found ")
|
||||
// -- XDPoS errors --
|
||||
|
||||
ErrNotXDPoS = errors.New("XDPoS not found in config")
|
||||
ErrNotFoundM1 = errors.New("list M1 not found ")
|
||||
ErrStopPreparingBlock = errors.New("stop calculating a block not verified by M2")
|
||||
|
||||
// -- EIP-7702 errors --
|
||||
|
||||
// Message validation errors:
|
||||
ErrEmptyAuthList = errors.New("EIP-7702 transaction with empty auth list")
|
||||
ErrSetCodeTxCreate = errors.New("EIP-7702 transaction cannot be used to create contract")
|
||||
)
|
||||
|
||||
// EIP-7702 state transition errors.
|
||||
// Note these are just informational, and do not cause tx execution abort.
|
||||
var (
|
||||
ErrAuthorizationWrongChainID = errors.New("EIP-7702 authorization chain ID mismatch")
|
||||
ErrAuthorizationNonceOverflow = errors.New("EIP-7702 authorization nonce > 64 bit")
|
||||
ErrAuthorizationInvalidSignature = errors.New("EIP-7702 authorization has invalid signature")
|
||||
ErrAuthorizationDestinationHasCode = errors.New("EIP-7702 authorization destination is a contract")
|
||||
ErrAuthorizationNonceMismatch = errors.New("EIP-7702 authorization nonce does not match current account nonce")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -89,6 +89,13 @@ func (j *journal) createContract(addr common.Address) {
|
|||
j.append(createContractChange{account: addr})
|
||||
}
|
||||
|
||||
func (j *journal) setCode(address common.Address, prevCode []byte) {
|
||||
j.append(codeChange{
|
||||
account: address,
|
||||
prevCode: prevCode,
|
||||
})
|
||||
}
|
||||
|
||||
type (
|
||||
// Changes to the account trie.
|
||||
createObjectChange struct {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"io"
|
||||
"maps"
|
||||
"math/big"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
|
|
@ -421,13 +422,11 @@ func (s *stateObject) CodeSize(db Database) int {
|
|||
return size
|
||||
}
|
||||
|
||||
func (s *stateObject) SetCode(codeHash common.Hash, code []byte) {
|
||||
prevCode := s.Code(s.db.db)
|
||||
s.db.journal.append(codeChange{
|
||||
account: s.address,
|
||||
prevCode: prevCode,
|
||||
})
|
||||
func (s *stateObject) SetCode(codeHash common.Hash, code []byte) []byte {
|
||||
prevCode := slices.Clone(s.code)
|
||||
s.db.journal.setCode(s.address, prevCode)
|
||||
s.setCode(codeHash, code)
|
||||
return prevCode
|
||||
}
|
||||
|
||||
func (s *stateObject) setCode(codeHash common.Hash, code []byte) {
|
||||
|
|
|
|||
|
|
@ -416,11 +416,12 @@ func (s *StateDB) SetNonce(addr common.Address, nonce uint64) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *StateDB) SetCode(addr common.Address, code []byte) {
|
||||
func (s *StateDB) SetCode(addr common.Address, code []byte) []byte {
|
||||
stateObject := s.GetOrNewStateObject(addr)
|
||||
if stateObject != nil {
|
||||
stateObject.SetCode(crypto.Keccak256Hash(code), code)
|
||||
return stateObject.SetCode(crypto.Keccak256Hash(code), code)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StateDB) SetState(addr common.Address, key, value common.Hash) common.Hash {
|
||||
|
|
|
|||
|
|
@ -172,9 +172,8 @@ func (s *hookedStateDB) SetNonce(address common.Address, nonce uint64) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) SetCode(address common.Address, code []byte) {
|
||||
prevCode := s.inner.GetCode(address)
|
||||
s.inner.SetCode(address, code)
|
||||
func (s *hookedStateDB) SetCode(address common.Address, code []byte) []byte {
|
||||
prevCode := s.inner.SetCode(address, code)
|
||||
if s.hooks.OnCodeChange != nil {
|
||||
prevHash := crypto.Keccak256Hash(prevCode)
|
||||
codeHash := crypto.Keccak256Hash(code)
|
||||
|
|
@ -184,6 +183,7 @@ func (s *hookedStateDB) SetCode(address common.Address, code []byte) {
|
|||
s.hooks.OnCodeChange(address, prevHash, prevCode, codeHash, code)
|
||||
}
|
||||
}
|
||||
return prevCode
|
||||
}
|
||||
|
||||
func (s *hookedStateDB) SetState(address common.Address, key common.Hash, value common.Hash) common.Hash {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import (
|
|||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/XinFinOrg/XDPoSChain/trie"
|
||||
"github.com/holiman/uint256"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
|
|
@ -51,15 +52,18 @@ func TestStateProcessorErrors(t *testing.T) {
|
|||
IstanbulBlock: big.NewInt(0),
|
||||
BerlinBlock: big.NewInt(0),
|
||||
LondonBlock: big.NewInt(0),
|
||||
ShanghaiBlock: big.NewInt(0),
|
||||
Eip1559Block: big.NewInt(0),
|
||||
CancunBlock: big.NewInt(0),
|
||||
PragueBlock: big.NewInt(0),
|
||||
Ethash: new(params.EthashConfig),
|
||||
}
|
||||
signer = types.LatestSigner(config)
|
||||
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
signer = types.LatestSigner(config)
|
||||
key1, _ = 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)
|
||||
signedTx, err := types.SignTx(tx, signer, key1)
|
||||
if err != nil {
|
||||
t.Fatalf("fail to sign tx: %v, err: %v", tx, err)
|
||||
}
|
||||
|
|
@ -73,9 +77,36 @@ func TestStateProcessorErrors(t *testing.T) {
|
|||
Gas: gasLimit,
|
||||
To: &to,
|
||||
Value: big.NewInt(0),
|
||||
}), signer, testKey)
|
||||
}), signer, key1)
|
||||
return tx
|
||||
}
|
||||
var mkDynamicCreationTx = func(nonce uint64, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, data []byte) *types.Transaction {
|
||||
tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{
|
||||
Nonce: nonce,
|
||||
GasTipCap: gasTipCap,
|
||||
GasFeeCap: gasFeeCap,
|
||||
Gas: gasLimit,
|
||||
Value: big.NewInt(0),
|
||||
Data: data,
|
||||
}), signer, key1)
|
||||
return tx
|
||||
}
|
||||
var mkSetCodeTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, authlist []types.Authorization) *types.Transaction {
|
||||
tx, err := types.SignTx(types.NewTx(&types.SetCodeTx{
|
||||
Nonce: nonce,
|
||||
GasTipCap: uint256.MustFromBig(gasTipCap),
|
||||
GasFeeCap: uint256.MustFromBig(gasFeeCap),
|
||||
Gas: gasLimit,
|
||||
To: to,
|
||||
Value: new(uint256.Int),
|
||||
AuthList: authlist,
|
||||
}), signer, key1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return tx
|
||||
}
|
||||
|
||||
{ // Tests against a 'recent' chain definition
|
||||
var (
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
|
|
@ -88,8 +119,9 @@ func TestStateProcessorErrors(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
genesis = gspec.MustCommit(db)
|
||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
||||
genesis = gspec.MustCommit(db)
|
||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{})
|
||||
tooBigInitCode = [params.MaxInitCodeSize + 1]byte{}
|
||||
)
|
||||
defer blockchain.Stop()
|
||||
bigNumber := new(big.Int).SetBytes(common.MaxHash.Bytes())
|
||||
|
|
@ -101,34 +133,34 @@ func TestStateProcessorErrors(t *testing.T) {
|
|||
}{
|
||||
{ // 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),
|
||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(12500000000), nil),
|
||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(12500000000), nil),
|
||||
},
|
||||
want: "nonce too low: address xdc71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1",
|
||||
want: "could not apply tx 1 [0xecd6a889a307155b3562cd64c86957e36fa58267cb4efbbe39aa692fd7aab09a]: 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",
|
||||
want: "could not apply tx 0 [0xdebad714ca7f363bd0d8121c4518ad48fa469ca81b0a081be3d10c17460f751b]: 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),
|
||||
makeTx(0, common.Address{}, big.NewInt(0), 21000000, big.NewInt(12500000000), nil),
|
||||
},
|
||||
want: "gas limit reached",
|
||||
want: "could not apply tx 0 [0x062b0e84f2d48f09f91e434fca8cb1fb864c4fb82f8bf27d58879ebe60c9f773]: gas limit reached",
|
||||
},
|
||||
{ // ErrInsufficientFundsForTransfer
|
||||
txs: []*types.Transaction{
|
||||
makeTx(0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(875000000), nil),
|
||||
makeTx(0, common.Address{}, big.NewInt(1000000000000000000), params.TxGas, big.NewInt(12500000000), nil),
|
||||
},
|
||||
want: "insufficient funds for gas * price + value: address xdc71562b71999873DB5b286dF957af199Ec94617F7",
|
||||
want: "could not apply tx 0 [0x50f89093bf5ad7f4ae6f9e3bad44d4dc130247ea0429df0cf78873584a76dfa1]: insufficient funds for gas * price + value: address xdc71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 1000262500000000000",
|
||||
},
|
||||
{ // 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",
|
||||
want: "could not apply tx 0 [0x4a69690c4b0cd85e64d0d9ea06302455b01e10a83db964d60281739752003440]: insufficient funds for gas * price + value: address xdc71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 18900000000000000000000",
|
||||
},
|
||||
// ErrGasUintOverflow
|
||||
// One missing 'core' error is ErrGasUintOverflow: "gas uint64 overflow",
|
||||
|
|
@ -136,21 +168,21 @@ func TestStateProcessorErrors(t *testing.T) {
|
|||
// 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),
|
||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(12500000000), nil),
|
||||
},
|
||||
want: "intrinsic gas too low: have 20000, want 21000",
|
||||
want: "could not apply tx 0 [0xa3484a466ffa8a88dc95e6ff520c853659dfc5507039c0b1452c2b845438771b]: 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),
|
||||
makeTx(0, common.Address{}, big.NewInt(0), params.TxGas*1000, big.NewInt(12500000000), nil),
|
||||
},
|
||||
want: "gas limit reached",
|
||||
want: "could not apply tx 0 [0x062b0e84f2d48f09f91e434fca8cb1fb864c4fb82f8bf27d58879ebe60c9f773]: 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, maxFeePerGas: 0 baseFee: 875000000",
|
||||
want: "could not apply tx 0 [0xc4ab868fef0c82ae0387b742aee87907f2d0fc528fc6ea0a021459fb0fc4a4a8]: max fee per gas less than block base fee: address xdc71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas: 0 baseFee: 12500000000",
|
||||
},
|
||||
{ // ErrTipVeryHigh
|
||||
txs: []*types.Transaction{
|
||||
|
|
@ -187,7 +219,26 @@ func TestStateProcessorErrors(t *testing.T) {
|
|||
},
|
||||
want: "could not apply tx 0 [0xd82a0c2519acfeac9a948258c47e784acd20651d9d80f9a1c67b4137651c3a24]: insufficient funds for gas * price + value: address xdc71562b71999873DB5b286dF957af199Ec94617F7 have 1000000000000000000 want 2431633873983640103894990685182446064918669677978451844828609264166175722438635000",
|
||||
},
|
||||
}[8:] {
|
||||
{ // ErrMaxInitCodeSizeExceeded
|
||||
txs: []*types.Transaction{
|
||||
mkDynamicCreationTx(0, 500000, common.Big0, big.NewInt(params.InitialBaseFee), tooBigInitCode[:]),
|
||||
},
|
||||
want: "could not apply tx 0 [0x42c498ac252e8943de9e8ab3267113b0a0cde54543df1ab0711b0d87ccca3e03]: max initcode size exceeded: code size 49153 limit 49152",
|
||||
},
|
||||
{ // ErrIntrinsicGas: Not enough gas to cover init code
|
||||
txs: []*types.Transaction{
|
||||
mkDynamicCreationTx(0, 54299, common.Big0, big.NewInt(params.InitialBaseFee), make([]byte, 320)),
|
||||
},
|
||||
want: "could not apply tx 0 [0x83f0bd65f2c2ad82de0da306aa93dea5e47d4ba0cd9f23ec4ce3fd0a3246da1c]: intrinsic gas too low: have 54299, want 54300",
|
||||
},
|
||||
{ // ErrEmptyAuthList
|
||||
txs: []*types.Transaction{
|
||||
mkSetCodeTx(0, common.Address{}, params.TxGas, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), nil),
|
||||
},
|
||||
want: "could not apply tx 0 [0x2fadb4fa7ccf8564edc21590f8d94a5b93a981b2bb2de8256978cb7361bc69de]: EIP-7702 transaction with empty auth list (sender 0x71562b71999873DB5b286dF957af199Ec94617F7)",
|
||||
},
|
||||
// ErrSetCodeTxCreate cannot be tested: it is impossible to create a SetCode-tx with nil `to`.
|
||||
} {
|
||||
block := GenerateBadBlock(t, genesis, ethash.NewFaker(), tt.txs, gspec.Config)
|
||||
_, err := blockchain.InsertChain(types.Blocks{block})
|
||||
if err == nil {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ func (result *ExecutionResult) Revert() []byte {
|
|||
}
|
||||
|
||||
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
|
||||
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation, isHomestead bool, isEIP3860 bool) (uint64, error) {
|
||||
func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Authorization, isContractCreation, isHomestead bool, isEIP3860 bool) (uint64, error) {
|
||||
// Set the starting gas for the raw transaction
|
||||
var gas uint64
|
||||
if isContractCreation && isHomestead {
|
||||
|
|
@ -101,6 +101,9 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation,
|
|||
gas += uint64(len(accessList)) * params.TxAccessListAddressGas
|
||||
gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas
|
||||
}
|
||||
if authList != nil {
|
||||
gas += uint64(len(authList)) * params.CallNewAccountGas
|
||||
}
|
||||
return gas, nil
|
||||
}
|
||||
|
||||
|
|
@ -127,6 +130,7 @@ type Message struct {
|
|||
BalanceTokenFee *big.Int
|
||||
Data []byte
|
||||
AccessList types.AccessList
|
||||
AuthList []types.Authorization
|
||||
|
||||
// When SkipNonceChecks is true, the message nonce is not checked against the
|
||||
// account nonce in state.
|
||||
|
|
@ -149,6 +153,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, balanceFee, blo
|
|||
Value: tx.Value(),
|
||||
Data: tx.Data(),
|
||||
AccessList: tx.AccessList(),
|
||||
AuthList: tx.AuthList(),
|
||||
SkipNonceChecks: false,
|
||||
SkipFromEOACheck: false,
|
||||
BalanceTokenFee: balanceFee,
|
||||
|
|
@ -302,10 +307,10 @@ func (st *StateTransition) preCheck() error {
|
|||
}
|
||||
if !msg.SkipFromEOACheck {
|
||||
// Make sure the sender is an EOA
|
||||
codeHash := st.state.GetCodeHash(msg.From)
|
||||
if codeHash != (common.Hash{}) && codeHash != types.EmptyCodeHash {
|
||||
return fmt.Errorf("%w: address %v, codehash: %s", ErrSenderNoEOA,
|
||||
msg.From.Hex(), codeHash)
|
||||
code := st.state.GetCode(msg.From)
|
||||
_, delegated := types.ParseDelegation(code)
|
||||
if len(code) > 0 && !delegated {
|
||||
return fmt.Errorf("%w: address %v, len(code): %d", ErrSenderNoEOA, msg.From.Hex(), len(code))
|
||||
}
|
||||
}
|
||||
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
|
||||
|
|
@ -333,6 +338,15 @@ func (st *StateTransition) preCheck() error {
|
|||
}
|
||||
}
|
||||
}
|
||||
// Check that EIP-7702 authorization list signatures are well formed.
|
||||
if msg.AuthList != nil {
|
||||
if msg.To == nil {
|
||||
return fmt.Errorf("%w (sender %v)", ErrSetCodeTxCreate, msg.From)
|
||||
}
|
||||
if len(msg.AuthList) == 0 {
|
||||
return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From)
|
||||
}
|
||||
}
|
||||
return st.buyGas()
|
||||
}
|
||||
|
||||
|
|
@ -373,7 +387,7 @@ func (st *StateTransition) TransitionDb(owner common.Address) (*ExecutionResult,
|
|||
)
|
||||
|
||||
// Check clauses 4-5, subtract intrinsic gas if everything is correct
|
||||
gas, err := IntrinsicGas(msg.Data, msg.AccessList, contractCreation, rules.IsHomestead, rules.IsEIP1559)
|
||||
gas, err := IntrinsicGas(msg.Data, msg.AccessList, msg.AuthList, contractCreation, rules.IsHomestead, rules.IsEIP1559)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -412,7 +426,26 @@ func (st *StateTransition) TransitionDb(owner common.Address) (*ExecutionResult,
|
|||
ret, _, st.gasRemaining, vmerr = st.evm.Create(sender, msg.Data, st.gasRemaining, msg.Value)
|
||||
} else {
|
||||
// Increment the nonce for the next transaction
|
||||
st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1)
|
||||
st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1)
|
||||
|
||||
// Apply EIP-7702 authorizations.
|
||||
if msg.AuthList != nil {
|
||||
for _, auth := range msg.AuthList {
|
||||
// Note errors are ignored, we simply skip invalid authorizations here.
|
||||
st.applyAuthorization(msg, &auth)
|
||||
}
|
||||
}
|
||||
|
||||
// Perform convenience warming of sender's delegation target. Although the
|
||||
// sender is already warmed in Prepare(..), it's possible a delegation to
|
||||
// the account was deployed during this transaction. To handle correctly,
|
||||
// simply wait until the final state of delegations is determined before
|
||||
// performing the resolution and warming.
|
||||
if addr, ok := types.ParseDelegation(st.state.GetCode(*msg.To)); ok {
|
||||
st.state.AddAddressToAccessList(addr)
|
||||
}
|
||||
|
||||
// Execute the transaction's call.
|
||||
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value)
|
||||
}
|
||||
|
||||
|
|
@ -449,6 +482,64 @@ func (st *StateTransition) TransitionDb(owner common.Address) (*ExecutionResult,
|
|||
}, nil
|
||||
}
|
||||
|
||||
// validateAuthorization validates an EIP-7702 authorization against the state.
|
||||
func (st *StateTransition) validateAuthorization(auth *types.Authorization) (authority common.Address, err error) {
|
||||
// Verify chain ID is 0 or equal to current chain ID.
|
||||
if auth.ChainID != 0 && st.evm.ChainConfig().ChainID.Uint64() != auth.ChainID {
|
||||
return authority, ErrAuthorizationWrongChainID
|
||||
}
|
||||
// Limit nonce to 2^64-1 per EIP-2681.
|
||||
if auth.Nonce+1 < auth.Nonce {
|
||||
return authority, ErrAuthorizationNonceOverflow
|
||||
}
|
||||
// Validate signature values and recover authority.
|
||||
authority, err = auth.Authority()
|
||||
if err != nil {
|
||||
return authority, fmt.Errorf("%w: %v", ErrAuthorizationInvalidSignature, err)
|
||||
}
|
||||
// Check the authority account
|
||||
// 1) doesn't have code or has existing delegation
|
||||
// 2) matches the auth's nonce
|
||||
//
|
||||
// Note it is added to the access list even if the authorization is invalid.
|
||||
st.state.AddAddressToAccessList(authority)
|
||||
code := st.state.GetCode(authority)
|
||||
if _, ok := types.ParseDelegation(code); len(code) != 0 && !ok {
|
||||
return authority, ErrAuthorizationDestinationHasCode
|
||||
}
|
||||
if have := st.state.GetNonce(authority); have != auth.Nonce {
|
||||
return authority, ErrAuthorizationNonceMismatch
|
||||
}
|
||||
return authority, nil
|
||||
}
|
||||
|
||||
// applyAuthorization applies an EIP-7702 code delegation to the state.
|
||||
func (st *StateTransition) applyAuthorization(msg *Message, auth *types.Authorization) error {
|
||||
authority, err := st.validateAuthorization(auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the account already exists in state, refund the new account cost
|
||||
// charged in the intrinsic calculation.
|
||||
if st.state.Exist(authority) {
|
||||
st.state.AddRefund(params.CallNewAccountGas - params.TxAuthTupleGas)
|
||||
}
|
||||
|
||||
// Update nonce and account code.
|
||||
st.state.SetNonce(authority, auth.Nonce+1)
|
||||
if auth.Address == (common.Address{}) {
|
||||
// Delegation to zero address means clear.
|
||||
st.state.SetCode(authority, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Otherwise install delegation to auth.Address.
|
||||
st.state.SetCode(authority, types.AddressToDelegation(auth.Address))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *StateTransition) refundGas(refundQuotient uint64) {
|
||||
// Apply refund counter, capped to a refund quotient
|
||||
refund := st.gasUsed() / refundQuotient
|
||||
|
|
|
|||
|
|
@ -687,7 +687,7 @@ func (pool *TxPool) validateTxBasics(tx *types.Transaction, local bool) error {
|
|||
return nil
|
||||
}
|
||||
// Ensure the transaction has more gas than the basic tx fee.
|
||||
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, true, pool.eip1559.Load())
|
||||
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.AuthList(), tx.To() == nil, true, pool.eip1559.Load())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
75
core/types/gen_authorization.go
Normal file
75
core/types/gen_authorization.go
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
var _ = (*authorizationMarshaling)(nil)
|
||||
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (a Authorization) MarshalJSON() ([]byte, error) {
|
||||
type Authorization struct {
|
||||
ChainID hexutil.Uint64 `json:"chainId" gencodec:"required"`
|
||||
Address common.Address `json:"address" gencodec:"required"`
|
||||
Nonce hexutil.Uint64 `json:"nonce" gencodec:"required"`
|
||||
V hexutil.Uint64 `json:"v" gencodec:"required"`
|
||||
R uint256.Int `json:"r" gencodec:"required"`
|
||||
S uint256.Int `json:"s" gencodec:"required"`
|
||||
}
|
||||
var enc Authorization
|
||||
enc.ChainID = hexutil.Uint64(a.ChainID)
|
||||
enc.Address = a.Address
|
||||
enc.Nonce = hexutil.Uint64(a.Nonce)
|
||||
enc.V = hexutil.Uint64(a.V)
|
||||
enc.R = a.R
|
||||
enc.S = a.S
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (a *Authorization) UnmarshalJSON(input []byte) error {
|
||||
type Authorization struct {
|
||||
ChainID *hexutil.Uint64 `json:"chainId" gencodec:"required"`
|
||||
Address *common.Address `json:"address" gencodec:"required"`
|
||||
Nonce *hexutil.Uint64 `json:"nonce" gencodec:"required"`
|
||||
V *hexutil.Uint64 `json:"v" gencodec:"required"`
|
||||
R *uint256.Int `json:"r" gencodec:"required"`
|
||||
S *uint256.Int `json:"s" gencodec:"required"`
|
||||
}
|
||||
var dec Authorization
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
if dec.ChainID == nil {
|
||||
return errors.New("missing required field 'chainId' for Authorization")
|
||||
}
|
||||
a.ChainID = uint64(*dec.ChainID)
|
||||
if dec.Address == nil {
|
||||
return errors.New("missing required field 'address' for Authorization")
|
||||
}
|
||||
a.Address = *dec.Address
|
||||
if dec.Nonce == nil {
|
||||
return errors.New("missing required field 'nonce' for Authorization")
|
||||
}
|
||||
a.Nonce = uint64(*dec.Nonce)
|
||||
if dec.V == nil {
|
||||
return errors.New("missing required field 'v' for Authorization")
|
||||
}
|
||||
a.V = uint8(*dec.V)
|
||||
if dec.R == nil {
|
||||
return errors.New("missing required field 'r' for Authorization")
|
||||
}
|
||||
a.R = *dec.R
|
||||
if dec.S == nil {
|
||||
return errors.New("missing required field 's' for Authorization")
|
||||
}
|
||||
a.S = *dec.S
|
||||
return nil
|
||||
}
|
||||
|
|
@ -215,7 +215,7 @@ func (r *Receipt) decodeTyped(b []byte) error {
|
|||
return errShortTypedReceipt
|
||||
}
|
||||
switch b[0] {
|
||||
case DynamicFeeTxType, AccessListTxType:
|
||||
case DynamicFeeTxType, AccessListTxType, SetCodeTxType:
|
||||
var data receiptRLP
|
||||
err := rlp.DecodeBytes(b[1:], &data)
|
||||
if err != nil {
|
||||
|
|
@ -389,7 +389,7 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
|
|||
}
|
||||
w.WriteByte(r.Type)
|
||||
switch r.Type {
|
||||
case AccessListTxType, DynamicFeeTxType:
|
||||
case AccessListTxType, DynamicFeeTxType, SetCodeTxType:
|
||||
rlp.Encode(w, data)
|
||||
default:
|
||||
// For unsupported types, write nothing. Since this is for
|
||||
|
|
|
|||
|
|
@ -45,9 +45,10 @@ var (
|
|||
|
||||
// Transaction types.
|
||||
const (
|
||||
LegacyTxType = iota
|
||||
AccessListTxType
|
||||
DynamicFeeTxType
|
||||
LegacyTxType = 0x00
|
||||
AccessListTxType = 0x01
|
||||
DynamicFeeTxType = 0x02
|
||||
SetCodeTxType = 0x04
|
||||
)
|
||||
|
||||
// Transaction is an Ethereum transaction.
|
||||
|
|
@ -195,6 +196,8 @@ func (tx *Transaction) decodeTyped(b []byte) (TxData, error) {
|
|||
inner = new(AccessListTx)
|
||||
case DynamicFeeTxType:
|
||||
inner = new(DynamicFeeTx)
|
||||
case SetCodeTxType:
|
||||
inner = new(SetCodeTx)
|
||||
default:
|
||||
return nil, ErrTxTypeNotSupported
|
||||
}
|
||||
|
|
@ -389,6 +392,15 @@ func (tx *Transaction) EffectiveGasTipIntCmp(other *big.Int, baseFee *big.Int) i
|
|||
return tx.EffectiveGasTipValue(baseFee).Cmp(other)
|
||||
}
|
||||
|
||||
// AuthList returns the authorizations list of the transaction.
|
||||
func (tx *Transaction) AuthList() []Authorization {
|
||||
setcodetx, ok := tx.inner.(*SetCodeTx)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return setcodetx.AuthList
|
||||
}
|
||||
|
||||
// Hash returns the transaction hash.
|
||||
func (tx *Transaction) Hash() common.Hash {
|
||||
if hash := tx.hash.Load(); hash != nil {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// txJSON is the JSON representation of transactions.
|
||||
|
|
@ -39,6 +40,7 @@ type txJSON struct {
|
|||
Value *hexutil.Big `json:"value"`
|
||||
Input *hexutil.Bytes `json:"input"`
|
||||
AccessList *AccessList `json:"accessList,omitempty"`
|
||||
AuthorizationList []Authorization `json:"authorizationList,omitempty"`
|
||||
V *hexutil.Big `json:"v"`
|
||||
R *hexutil.Big `json:"r"`
|
||||
S *hexutil.Big `json:"s"`
|
||||
|
|
@ -121,8 +123,24 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
|||
enc.S = (*hexutil.Big)(itx.S)
|
||||
yparity := itx.V.Uint64()
|
||||
enc.YParity = (*hexutil.Uint64)(&yparity)
|
||||
}
|
||||
|
||||
case *SetCodeTx:
|
||||
enc.ChainID = (*hexutil.Big)(new(big.Int).SetUint64(itx.ChainID))
|
||||
enc.Nonce = (*hexutil.Uint64)(&itx.Nonce)
|
||||
enc.To = tx.To()
|
||||
enc.Gas = (*hexutil.Uint64)(&itx.Gas)
|
||||
enc.MaxFeePerGas = (*hexutil.Big)(itx.GasFeeCap.ToBig())
|
||||
enc.MaxPriorityFeePerGas = (*hexutil.Big)(itx.GasTipCap.ToBig())
|
||||
enc.Value = (*hexutil.Big)(itx.Value.ToBig())
|
||||
enc.Input = (*hexutil.Bytes)(&itx.Data)
|
||||
enc.AccessList = &itx.AccessList
|
||||
enc.AuthorizationList = itx.AuthList
|
||||
enc.V = (*hexutil.Big)(itx.V.ToBig())
|
||||
enc.R = (*hexutil.Big)(itx.R.ToBig())
|
||||
enc.S = (*hexutil.Big)(itx.S.ToBig())
|
||||
yparity := itx.V.Uint64()
|
||||
enc.YParity = (*hexutil.Uint64)(&yparity)
|
||||
}
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
|
|
@ -299,6 +317,81 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
|||
}
|
||||
}
|
||||
|
||||
case SetCodeTxType:
|
||||
var itx SetCodeTx
|
||||
inner = &itx
|
||||
if dec.ChainID == nil {
|
||||
return errors.New("missing required field 'chainId' in transaction")
|
||||
}
|
||||
itx.ChainID = dec.ChainID.ToInt().Uint64()
|
||||
if dec.Nonce == nil {
|
||||
return errors.New("missing required field 'nonce' in transaction")
|
||||
}
|
||||
itx.Nonce = uint64(*dec.Nonce)
|
||||
if dec.To == nil {
|
||||
return errors.New("missing required field 'to' in transaction")
|
||||
}
|
||||
itx.To = *dec.To
|
||||
if dec.Gas == nil {
|
||||
return errors.New("missing required field 'gas' for txdata")
|
||||
}
|
||||
itx.Gas = uint64(*dec.Gas)
|
||||
if dec.MaxPriorityFeePerGas == nil {
|
||||
return errors.New("missing required field 'maxPriorityFeePerGas' for txdata")
|
||||
}
|
||||
itx.GasTipCap = uint256.MustFromBig((*big.Int)(dec.MaxPriorityFeePerGas))
|
||||
if dec.MaxFeePerGas == nil {
|
||||
return errors.New("missing required field 'maxFeePerGas' for txdata")
|
||||
}
|
||||
itx.GasFeeCap = uint256.MustFromBig((*big.Int)(dec.MaxFeePerGas))
|
||||
if dec.Value == nil {
|
||||
return errors.New("missing required field 'value' in transaction")
|
||||
}
|
||||
itx.Value = uint256.MustFromBig((*big.Int)(dec.Value))
|
||||
if dec.Input == nil {
|
||||
return errors.New("missing required field 'input' in transaction")
|
||||
}
|
||||
itx.Data = *dec.Input
|
||||
if dec.AccessList != nil {
|
||||
itx.AccessList = *dec.AccessList
|
||||
}
|
||||
if dec.AuthorizationList == nil {
|
||||
return errors.New("missing required field 'authorizationList' in transaction")
|
||||
}
|
||||
itx.AuthList = dec.AuthorizationList
|
||||
|
||||
// signature R
|
||||
var overflow bool
|
||||
if dec.R == nil {
|
||||
return errors.New("missing required field 'r' in transaction")
|
||||
}
|
||||
itx.R, overflow = uint256.FromBig((*big.Int)(dec.R))
|
||||
if overflow {
|
||||
return errors.New("'r' value overflows uint256")
|
||||
}
|
||||
// signature S
|
||||
if dec.S == nil {
|
||||
return errors.New("missing required field 's' in transaction")
|
||||
}
|
||||
itx.S, overflow = uint256.FromBig((*big.Int)(dec.S))
|
||||
if overflow {
|
||||
return errors.New("'s' value overflows uint256")
|
||||
}
|
||||
// signature V
|
||||
vbig, err := dec.yParityValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
itx.V, overflow = uint256.FromBig(vbig)
|
||||
if overflow {
|
||||
return errors.New("'v' value overflows uint256")
|
||||
}
|
||||
if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 {
|
||||
if err := sanityCheckSignature(vbig, itx.R.ToBig(), itx.S.ToBig(), false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return ErrTxTypeNotSupported
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
|
|
@ -41,6 +42,8 @@ type sigCache struct {
|
|||
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
|
||||
var signer Signer
|
||||
switch {
|
||||
case config.IsPrague(blockNumber):
|
||||
signer = NewPragueSigner(config.ChainID)
|
||||
case config.IsEIP1559(blockNumber):
|
||||
signer = NewLondonSigner(config.ChainID)
|
||||
case config.IsEIP155(blockNumber):
|
||||
|
|
@ -61,15 +64,20 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
|
|||
// Use this in transaction-handling code where the current block number is unknown. If you
|
||||
// have the current block number available, use MakeSigner instead.
|
||||
func LatestSigner(config *params.ChainConfig) Signer {
|
||||
var signer Signer
|
||||
if config.ChainID != nil {
|
||||
if common.Eip1559Block.Uint64() != 9999999999 || config.Eip1559Block != nil {
|
||||
return NewLondonSigner(config.ChainID)
|
||||
}
|
||||
if config.EIP155Block != nil {
|
||||
return NewEIP155Signer(config.ChainID)
|
||||
switch {
|
||||
case common.PragueBlock.Int64() != math.MaxInt64 || config.PragueBlock != nil:
|
||||
signer = NewPragueSigner(config.ChainID)
|
||||
case common.Eip1559Block.Int64() != math.MaxInt64 || config.Eip1559Block != nil:
|
||||
signer = NewLondonSigner(config.ChainID)
|
||||
case config.EIP155Block != nil:
|
||||
signer = NewEIP155Signer(config.ChainID)
|
||||
default:
|
||||
signer = HomesteadSigner{}
|
||||
}
|
||||
}
|
||||
return HomesteadSigner{}
|
||||
return signer
|
||||
}
|
||||
|
||||
// LatestSignerForChainID returns the 'most permissive' Signer available. Specifically,
|
||||
|
|
@ -80,10 +88,13 @@ func LatestSigner(config *params.ChainConfig) Signer {
|
|||
// configuration are unknown. If you have a ChainConfig, use LatestSigner instead.
|
||||
// If you have a ChainConfig and know the current block number, use MakeSigner instead.
|
||||
func LatestSignerForChainID(chainID *big.Int) Signer {
|
||||
if chainID == nil {
|
||||
return HomesteadSigner{}
|
||||
var signer Signer
|
||||
if chainID != nil {
|
||||
signer = NewPragueSigner(chainID)
|
||||
} else {
|
||||
signer = HomesteadSigner{}
|
||||
}
|
||||
return NewLondonSigner(chainID)
|
||||
return signer
|
||||
}
|
||||
|
||||
// SignTx signs the transaction using the given signer and private key.
|
||||
|
|
@ -163,6 +174,76 @@ type Signer interface {
|
|||
Equal(Signer) bool
|
||||
}
|
||||
|
||||
type pragueSigner struct{ londonSigner }
|
||||
|
||||
// NewPragueSigner returns a signer that accepts
|
||||
// - EIP-7702 set code transactions
|
||||
// - EIP-1559 dynamic fee transactions
|
||||
// - EIP-2930 access list transactions,
|
||||
// - EIP-155 replay protected transactions, and
|
||||
// - legacy Homestead transactions.
|
||||
func NewPragueSigner(chainId *big.Int) Signer {
|
||||
signer, _ := NewLondonSigner(chainId).(londonSigner)
|
||||
return pragueSigner{signer}
|
||||
}
|
||||
|
||||
func (s pragueSigner) Sender(tx *Transaction) (common.Address, error) {
|
||||
if tx.Type() != SetCodeTxType {
|
||||
return s.londonSigner.Sender(tx)
|
||||
}
|
||||
V, R, S := tx.RawSignatureValues()
|
||||
|
||||
// Set code txs are defined to use 0 and 1 as their recovery
|
||||
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
||||
V = new(big.Int).Add(V, big.NewInt(27))
|
||||
if tx.ChainId().Cmp(s.chainId) != 0 {
|
||||
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
|
||||
}
|
||||
return recoverPlain(s.Hash(tx), R, S, V, true)
|
||||
}
|
||||
|
||||
func (s pragueSigner) Equal(s2 Signer) bool {
|
||||
x, ok := s2.(pragueSigner)
|
||||
return ok && x.chainId.Cmp(s.chainId) == 0
|
||||
}
|
||||
|
||||
func (s pragueSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
|
||||
txdata, ok := tx.inner.(*SetCodeTx)
|
||||
if !ok {
|
||||
return s.londonSigner.SignatureValues(tx, sig)
|
||||
}
|
||||
// Check that chain ID of tx matches the signer. We also accept ID zero here,
|
||||
// because it indicates that the chain ID was not specified in the tx.
|
||||
if txdata.ChainID != 0 && new(big.Int).SetUint64(txdata.ChainID).Cmp(s.chainId) != 0 {
|
||||
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId)
|
||||
}
|
||||
R, S, _ = decodeSignature(sig)
|
||||
V = big.NewInt(int64(sig[64]))
|
||||
return R, S, V, nil
|
||||
}
|
||||
|
||||
// Hash returns the hash to be signed by the sender.
|
||||
// It does not uniquely identify the transaction.
|
||||
func (s pragueSigner) Hash(tx *Transaction) common.Hash {
|
||||
if tx.Type() != SetCodeTxType {
|
||||
return s.londonSigner.Hash(tx)
|
||||
}
|
||||
return prefixedRlpHash(
|
||||
tx.Type(),
|
||||
[]interface{}{
|
||||
s.chainId,
|
||||
tx.Nonce(),
|
||||
tx.GasTipCap(),
|
||||
tx.GasFeeCap(),
|
||||
tx.Gas(),
|
||||
tx.To(),
|
||||
tx.Value(),
|
||||
tx.Data(),
|
||||
tx.AccessList(),
|
||||
tx.AuthList(),
|
||||
})
|
||||
}
|
||||
|
||||
type londonSigner struct{ eip2930Signer }
|
||||
|
||||
// NewLondonSigner returns a signer that accepts
|
||||
|
|
|
|||
226
core/types/tx_setcode.go
Normal file
226
core/types/tx_setcode.go
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// DelegationPrefix is used by code to denote the account is delegating to
|
||||
// another account.
|
||||
var DelegationPrefix = []byte{0xef, 0x01, 0x00}
|
||||
|
||||
// ParseDelegation tries to parse the address from a delegation slice.
|
||||
func ParseDelegation(b []byte) (common.Address, bool) {
|
||||
if len(b) != 23 || !bytes.HasPrefix(b, DelegationPrefix) {
|
||||
return common.Address{}, false
|
||||
}
|
||||
return common.BytesToAddress(b[len(DelegationPrefix):]), true
|
||||
}
|
||||
|
||||
// AddressToDelegation adds the delegation prefix to the specified address.
|
||||
func AddressToDelegation(addr common.Address) []byte {
|
||||
return append(DelegationPrefix, addr.Bytes()...)
|
||||
}
|
||||
|
||||
// SetCodeTx implements the EIP-7702 transaction type which temporarily installs
|
||||
// the code at the signer's address.
|
||||
type SetCodeTx struct {
|
||||
ChainID uint64
|
||||
Nonce uint64
|
||||
GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas
|
||||
GasFeeCap *uint256.Int // a.k.a. maxFeePerGas
|
||||
Gas uint64
|
||||
To common.Address
|
||||
Value *uint256.Int
|
||||
Data []byte
|
||||
AccessList AccessList
|
||||
AuthList []Authorization
|
||||
|
||||
// Signature values
|
||||
V *uint256.Int `json:"v" gencodec:"required"`
|
||||
R *uint256.Int `json:"r" gencodec:"required"`
|
||||
S *uint256.Int `json:"s" gencodec:"required"`
|
||||
}
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type Authorization -field-override authorizationMarshaling -out gen_authorization.go
|
||||
|
||||
// Authorization is an authorization from an account to deploy code at its address.
|
||||
type Authorization struct {
|
||||
ChainID uint64 `json:"chainId" gencodec:"required"`
|
||||
Address common.Address `json:"address" gencodec:"required"`
|
||||
Nonce uint64 `json:"nonce" gencodec:"required"`
|
||||
V uint8 `json:"v" gencodec:"required"`
|
||||
R uint256.Int `json:"r" gencodec:"required"`
|
||||
S uint256.Int `json:"s" gencodec:"required"`
|
||||
}
|
||||
|
||||
// field type overrides for gencodec
|
||||
type authorizationMarshaling struct {
|
||||
ChainID hexutil.Uint64
|
||||
Nonce hexutil.Uint64
|
||||
V hexutil.Uint64
|
||||
}
|
||||
|
||||
// SignAuth signs the provided authorization.
|
||||
func SignAuth(auth Authorization, prv *ecdsa.PrivateKey) (Authorization, error) {
|
||||
sighash := auth.sigHash()
|
||||
sig, err := crypto.Sign(sighash[:], prv)
|
||||
if err != nil {
|
||||
return Authorization{}, err
|
||||
}
|
||||
return auth.withSignature(sig), nil
|
||||
}
|
||||
|
||||
// withSignature updates the signature of an Authorization to be equal the
|
||||
// decoded signature provided in sig.
|
||||
func (a *Authorization) withSignature(sig []byte) Authorization {
|
||||
r, s, _ := decodeSignature(sig)
|
||||
return Authorization{
|
||||
ChainID: a.ChainID,
|
||||
Address: a.Address,
|
||||
Nonce: a.Nonce,
|
||||
V: sig[64],
|
||||
R: *uint256.MustFromBig(r),
|
||||
S: *uint256.MustFromBig(s),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Authorization) sigHash() common.Hash {
|
||||
return prefixedRlpHash(0x05, []any{
|
||||
a.ChainID,
|
||||
a.Address,
|
||||
a.Nonce,
|
||||
})
|
||||
}
|
||||
|
||||
// Authority recovers the authorizing account of an authorization.
|
||||
func (a *Authorization) Authority() (common.Address, error) {
|
||||
sighash := a.sigHash()
|
||||
if !crypto.ValidateSignatureValues(a.V, a.R.ToBig(), a.S.ToBig(), true) {
|
||||
return common.Address{}, ErrInvalidSig
|
||||
}
|
||||
// encode the signature in uncompressed format
|
||||
var sig [crypto.SignatureLength]byte
|
||||
a.R.WriteToSlice(sig[:32])
|
||||
a.S.WriteToSlice(sig[32:64])
|
||||
sig[64] = a.V
|
||||
// recover the public key from the signature
|
||||
pub, err := crypto.Ecrecover(sighash[:], sig[:])
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
if len(pub) == 0 || pub[0] != 4 {
|
||||
return common.Address{}, errors.New("invalid public key")
|
||||
}
|
||||
var addr common.Address
|
||||
copy(addr[:], crypto.Keccak256(pub[1:])[12:])
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// copy creates a deep copy of the transaction data and initializes all fields.
|
||||
func (tx *SetCodeTx) copy() TxData {
|
||||
cpy := &SetCodeTx{
|
||||
Nonce: tx.Nonce,
|
||||
To: tx.To,
|
||||
Data: common.CopyBytes(tx.Data),
|
||||
Gas: tx.Gas,
|
||||
// These are copied below.
|
||||
AccessList: make(AccessList, len(tx.AccessList)),
|
||||
AuthList: make([]Authorization, len(tx.AuthList)),
|
||||
Value: new(uint256.Int),
|
||||
ChainID: tx.ChainID,
|
||||
GasTipCap: new(uint256.Int),
|
||||
GasFeeCap: new(uint256.Int),
|
||||
V: new(uint256.Int),
|
||||
R: new(uint256.Int),
|
||||
S: new(uint256.Int),
|
||||
}
|
||||
copy(cpy.AccessList, tx.AccessList)
|
||||
copy(cpy.AuthList, tx.AuthList)
|
||||
if tx.Value != nil {
|
||||
cpy.Value.Set(tx.Value)
|
||||
}
|
||||
if tx.GasTipCap != nil {
|
||||
cpy.GasTipCap.Set(tx.GasTipCap)
|
||||
}
|
||||
if tx.GasFeeCap != nil {
|
||||
cpy.GasFeeCap.Set(tx.GasFeeCap)
|
||||
}
|
||||
if tx.V != nil {
|
||||
cpy.V.Set(tx.V)
|
||||
}
|
||||
if tx.R != nil {
|
||||
cpy.R.Set(tx.R)
|
||||
}
|
||||
if tx.S != nil {
|
||||
cpy.S.Set(tx.S)
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
// accessors for innerTx.
|
||||
func (tx *SetCodeTx) txType() byte { return SetCodeTxType }
|
||||
func (tx *SetCodeTx) chainID() *big.Int { return big.NewInt(int64(tx.ChainID)) }
|
||||
func (tx *SetCodeTx) accessList() AccessList { return tx.AccessList }
|
||||
func (tx *SetCodeTx) data() []byte { return tx.Data }
|
||||
func (tx *SetCodeTx) gas() uint64 { return tx.Gas }
|
||||
func (tx *SetCodeTx) gasFeeCap() *big.Int { return tx.GasFeeCap.ToBig() }
|
||||
func (tx *SetCodeTx) gasTipCap() *big.Int { return tx.GasTipCap.ToBig() }
|
||||
func (tx *SetCodeTx) gasPrice() *big.Int { return tx.GasFeeCap.ToBig() }
|
||||
func (tx *SetCodeTx) value() *big.Int { return tx.Value.ToBig() }
|
||||
func (tx *SetCodeTx) nonce() uint64 { return tx.Nonce }
|
||||
func (tx *SetCodeTx) to() *common.Address { tmp := tx.To; return &tmp }
|
||||
|
||||
func (tx *SetCodeTx) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int {
|
||||
if baseFee == nil {
|
||||
return dst.Set(tx.GasFeeCap.ToBig())
|
||||
}
|
||||
tip := dst.Sub(tx.GasFeeCap.ToBig(), baseFee)
|
||||
if tip.Cmp(tx.GasTipCap.ToBig()) > 0 {
|
||||
tip.Set(tx.GasTipCap.ToBig())
|
||||
}
|
||||
return tip.Add(tip, baseFee)
|
||||
}
|
||||
|
||||
func (tx *SetCodeTx) rawSignatureValues() (v, r, s *big.Int) {
|
||||
return tx.V.ToBig(), tx.R.ToBig(), tx.S.ToBig()
|
||||
}
|
||||
|
||||
func (tx *SetCodeTx) setSignatureValues(chainID, v, r, s *big.Int) {
|
||||
tx.ChainID = chainID.Uint64()
|
||||
tx.V.SetFromBig(v)
|
||||
tx.R.SetFromBig(r)
|
||||
tx.S.SetFromBig(s)
|
||||
}
|
||||
|
||||
func (tx *SetCodeTx) encode(b *bytes.Buffer) error {
|
||||
return rlp.Encode(b, tx)
|
||||
}
|
||||
|
||||
func (tx *SetCodeTx) decode(input []byte) error {
|
||||
return rlp.DecodeBytes(input, tx)
|
||||
}
|
||||
70
core/types/tx_setcode_test.go
Normal file
70
core/types/tx_setcode_test.go
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
)
|
||||
|
||||
// TestParseDelegation tests a few possible delegation designator values and
|
||||
// ensures they are parsed correctly.
|
||||
func TestParseDelegation(t *testing.T) {
|
||||
addr := common.Address{0x42}
|
||||
for _, tt := range []struct {
|
||||
val []byte
|
||||
want *common.Address
|
||||
}{
|
||||
{ // simple correct delegation
|
||||
val: append(DelegationPrefix, addr.Bytes()...),
|
||||
want: &addr,
|
||||
},
|
||||
{ // wrong address size
|
||||
val: append(DelegationPrefix, addr.Bytes()[0:19]...),
|
||||
},
|
||||
{ // short address
|
||||
val: append(DelegationPrefix, 0x42),
|
||||
},
|
||||
{ // long address
|
||||
val: append(append(DelegationPrefix, addr.Bytes()...), 0x42),
|
||||
},
|
||||
{ // wrong prefix size
|
||||
val: append(DelegationPrefix[:2], addr.Bytes()...),
|
||||
},
|
||||
{ // wrong prefix
|
||||
val: append([]byte{0xef, 0x01, 0x01}, addr.Bytes()...),
|
||||
},
|
||||
{ // wrong prefix
|
||||
val: append([]byte{0xef, 0x00, 0x00}, addr.Bytes()...),
|
||||
},
|
||||
{ // no prefix
|
||||
val: addr.Bytes(),
|
||||
},
|
||||
{ // no address
|
||||
val: DelegationPrefix,
|
||||
},
|
||||
} {
|
||||
got, ok := ParseDelegation(tt.val)
|
||||
if ok && tt.want == nil {
|
||||
t.Fatalf("expected fail, got %s", got.Hex())
|
||||
}
|
||||
if !ok && tt.want != nil {
|
||||
t.Fatalf("failed to parse, want %s", tt.want.Hex())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,8 +18,11 @@ package vm
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
|
@ -36,6 +39,7 @@ var activators = map[int]func(*JumpTable){
|
|||
1884: enable1884,
|
||||
1344: enable1344,
|
||||
1153: enable1153,
|
||||
7702: enable7702,
|
||||
}
|
||||
|
||||
// EnableEIP enables the given EIP on the config.
|
||||
|
|
@ -308,3 +312,68 @@ func enable6780(jt *JumpTable) {
|
|||
maxStack: maxStack(1, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// opExtCodeCopyEIP7702 implements the EIP-7702 variation of opExtCodeCopy.
|
||||
func opExtCodeCopyEIP7702(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||
var (
|
||||
stack = scope.Stack
|
||||
a = stack.pop()
|
||||
memOffset = stack.pop()
|
||||
codeOffset = stack.pop()
|
||||
length = stack.pop()
|
||||
)
|
||||
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||
if overflow {
|
||||
uint64CodeOffset = math.MaxUint64
|
||||
}
|
||||
code := evm.StateDB.GetCode(common.Address(a.Bytes20()))
|
||||
if _, ok := types.ParseDelegation(code); ok {
|
||||
code = types.DelegationPrefix[:2]
|
||||
}
|
||||
codeCopy := getData(code, uint64CodeOffset, length.Uint64())
|
||||
scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// opExtCodeSizeEIP7702 implements the EIP-7702 variation of opExtCodeSize.
|
||||
func opExtCodeSizeEIP7702(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||
slot := scope.Stack.peek()
|
||||
code := evm.StateDB.GetCode(common.Address(slot.Bytes20()))
|
||||
if _, ok := types.ParseDelegation(code); ok {
|
||||
code = types.DelegationPrefix[:2]
|
||||
}
|
||||
slot.SetUint64(uint64(len(code)))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// opExtCodeHashEIP7702 implements the EIP-7702 variation of opExtCodeHash.
|
||||
func opExtCodeHashEIP7702(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
|
||||
slot := scope.Stack.peek()
|
||||
addr := common.Address(slot.Bytes20())
|
||||
if evm.StateDB.Empty(addr) {
|
||||
slot.Clear()
|
||||
return nil, nil
|
||||
}
|
||||
code := evm.StateDB.GetCode(addr)
|
||||
if _, ok := types.ParseDelegation(code); ok {
|
||||
// If the code is a delegation, return the prefix without version.
|
||||
slot.SetBytes(crypto.Keccak256(types.DelegationPrefix[:2]))
|
||||
} else {
|
||||
// Otherwise, return normal code hash.
|
||||
slot.SetBytes(evm.StateDB.GetCodeHash(addr).Bytes())
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// enable7702 enables the EIP-7702 changes to support delegation designators.
|
||||
func enable7702(jt *JumpTable) {
|
||||
jt[EXTCODECOPY].execute = opExtCodeCopyEIP7702
|
||||
jt[EXTCODESIZE].execute = opExtCodeSizeEIP7702
|
||||
jt[EXTCODEHASH].execute = opExtCodeHashEIP7702
|
||||
|
||||
jt[CALL].dynamicGas = gasCallEIP7702
|
||||
jt[CALLCODE].dynamicGas = gasCallCodeEIP7702
|
||||
jt[STATICCALL].dynamicGas = gasStaticCallEIP7702
|
||||
jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP7702
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,9 +141,8 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStat
|
|||
evm.precompiles = activePrecompiledContracts(evm.chainRules)
|
||||
|
||||
switch {
|
||||
// TODO(daniel): define pragueInstructionSet
|
||||
// case evm.chainRules.IsPrague:
|
||||
// evm.table = &pragueInstructionSet
|
||||
case evm.chainRules.IsPrague:
|
||||
evm.table = &pragueInstructionSet
|
||||
case evm.chainRules.IsCancun:
|
||||
evm.table = &cancunInstructionSet
|
||||
case evm.chainRules.IsEIP1559:
|
||||
|
|
@ -251,7 +250,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
} else {
|
||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||
// The contract is a scoped environment for this execution context only.
|
||||
code := evm.StateDB.GetCode(addr)
|
||||
code := evm.resolveCode(addr)
|
||||
if len(code) == 0 {
|
||||
ret, err = nil, nil // gas is unchanged
|
||||
} else {
|
||||
|
|
@ -259,7 +258,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
// If the account has no code, we can abort here
|
||||
// The depth-check is already done, and precompiles handled above
|
||||
contract := NewContract(caller, AccountRef(addrCopy), value, gas)
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), code)
|
||||
contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), code)
|
||||
ret, err = evm.Run(contract, input, false)
|
||||
gas = contract.Gas
|
||||
}
|
||||
|
|
@ -319,7 +318,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
|||
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||
// The contract is a scoped environment for this execution context only.
|
||||
contract := NewContract(caller, AccountRef(caller.Address()), value, gas)
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
||||
contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), evm.resolveCode(addrCopy))
|
||||
ret, err = evm.Run(contract, input, false)
|
||||
gas = contract.Gas
|
||||
}
|
||||
|
|
@ -366,7 +365,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
|||
addrCopy := addr
|
||||
// Initialise a new contract and make initialise the delegate values
|
||||
contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate()
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
||||
contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), evm.resolveCode(addrCopy))
|
||||
ret, err = evm.Run(contract, input, false)
|
||||
gas = contract.Gas
|
||||
}
|
||||
|
|
@ -423,7 +422,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
|||
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||
// The contract is a scoped environment for this execution context only.
|
||||
contract := NewContract(caller, AccountRef(addrCopy), new(big.Int), gas)
|
||||
contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy))
|
||||
contract.SetCallCode(&addrCopy, evm.resolveCodeHash(addrCopy), evm.resolveCode(addrCopy))
|
||||
// When an error was returned by the EVM or when setting the creation code
|
||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||
// when we're in Homestead this also counts for code storage gas errors.
|
||||
|
|
@ -564,6 +563,35 @@ func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *
|
|||
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2)
|
||||
}
|
||||
|
||||
// resolveCode returns the code associated with the provided account. After
|
||||
// Prague, it can also resolve code pointed to by a delegation designator.
|
||||
func (evm *EVM) resolveCode(addr common.Address) []byte {
|
||||
code := evm.StateDB.GetCode(addr)
|
||||
if !evm.chainRules.IsPrague {
|
||||
return code
|
||||
}
|
||||
if target, ok := types.ParseDelegation(code); ok {
|
||||
// Note we only follow one level of delegation.
|
||||
return evm.StateDB.GetCode(target)
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
// resolveCodeHash returns the code hash associated with the provided address.
|
||||
// After Prague, it can also resolve code hash of the account pointed to by a
|
||||
// delegation designator. Although this is not accessible in the EVM it is used
|
||||
// internally to associate jumpdest analysis to code.
|
||||
func (evm *EVM) resolveCodeHash(addr common.Address) common.Hash {
|
||||
if evm.chainRules.IsPrague {
|
||||
code := evm.StateDB.GetCode(addr)
|
||||
if target, ok := types.ParseDelegation(code); ok {
|
||||
// Note we only follow one level of delegation.
|
||||
return evm.StateDB.GetCodeHash(target)
|
||||
}
|
||||
}
|
||||
return evm.StateDB.GetCodeHash(addr)
|
||||
}
|
||||
|
||||
// ChainConfig returns the environment's chain configuration
|
||||
func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ type StateDB interface {
|
|||
|
||||
GetCodeHash(common.Address) common.Hash
|
||||
GetCode(common.Address) []byte
|
||||
SetCode(common.Address, []byte)
|
||||
|
||||
// SetCode sets the new code for the address, and returns the previous code, if any.
|
||||
SetCode(common.Address, []byte) []byte
|
||||
GetCodeSize(common.Address) int
|
||||
|
||||
AddRefund(uint64)
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ var (
|
|||
shanghaiInstructionSet = newShanghaiInstructionSet()
|
||||
eip1559InstructionSet = newEip1559InstructionSet()
|
||||
cancunInstructionSet = newCancunInstructionSet()
|
||||
pragueInstructionSet = newPragueInstructionSet()
|
||||
)
|
||||
|
||||
// JumpTable contains the EVM opcodes supported at a given fork.
|
||||
|
|
@ -81,6 +82,12 @@ func validate(jt JumpTable) JumpTable {
|
|||
return jt
|
||||
}
|
||||
|
||||
func newPragueInstructionSet() JumpTable {
|
||||
instructionSet := newCancunInstructionSet()
|
||||
enable7702(&instructionSet) // EIP-7702 Setcode transaction type
|
||||
return validate(instructionSet)
|
||||
}
|
||||
|
||||
func newCancunInstructionSet() JumpTable {
|
||||
instructionSet := newEip1559InstructionSet()
|
||||
enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/math"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/tracing"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
)
|
||||
|
||||
|
|
@ -248,3 +249,70 @@ func makeSelfdestructGasFn(refundsEnabled bool) gasFunc {
|
|||
}
|
||||
return gasFunc
|
||||
}
|
||||
|
||||
var (
|
||||
gasCallEIP7702 = makeCallVariantGasCallEIP7702(gasCall)
|
||||
gasDelegateCallEIP7702 = makeCallVariantGasCallEIP7702(gasDelegateCall)
|
||||
gasStaticCallEIP7702 = makeCallVariantGasCallEIP7702(gasStaticCall)
|
||||
gasCallCodeEIP7702 = makeCallVariantGasCallEIP7702(gasCallCode)
|
||||
)
|
||||
|
||||
func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc {
|
||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||
var (
|
||||
total uint64 // total dynamic gas used
|
||||
addr = common.Address(stack.Back(1).Bytes20())
|
||||
)
|
||||
|
||||
// Check slot presence in the access list
|
||||
if !evm.StateDB.AddressInAccessList(addr) {
|
||||
evm.StateDB.AddAddressToAccessList(addr)
|
||||
// The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so
|
||||
// the cost to charge for cold access, if any, is Cold - Warm
|
||||
coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
|
||||
// Charge the remaining difference here already, to correctly calculate available
|
||||
// gas for call
|
||||
if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
||||
return 0, ErrOutOfGas
|
||||
}
|
||||
total += coldCost
|
||||
}
|
||||
|
||||
// Check if code is a delegation and if so, charge for resolution.
|
||||
if target, ok := types.ParseDelegation(evm.StateDB.GetCode(addr)); ok {
|
||||
var cost uint64
|
||||
if evm.StateDB.AddressInAccessList(target) {
|
||||
cost = params.WarmStorageReadCostEIP2929
|
||||
} else {
|
||||
evm.StateDB.AddAddressToAccessList(target)
|
||||
cost = params.ColdAccountAccessCostEIP2929
|
||||
}
|
||||
if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
||||
return 0, ErrOutOfGas
|
||||
}
|
||||
total += cost
|
||||
}
|
||||
|
||||
// Now call the old calculator, which takes into account
|
||||
// - create new account
|
||||
// - transfer value
|
||||
// - memory expansion
|
||||
// - 63/64ths rule
|
||||
old, err := oldCalculator(evm, contract, stack, mem, memorySize)
|
||||
if err != nil {
|
||||
return old, err
|
||||
}
|
||||
|
||||
// Temporarily add the gas charge back to the contract and return value. By
|
||||
// adding it to the return, it will be charged outside of this function, as
|
||||
// part of the dynamic gas. This will ensure it is correctly reported to
|
||||
// tracers.
|
||||
contract.Gas += total
|
||||
|
||||
var overflow bool
|
||||
if total, overflow = math.SafeAdd(old, total); overflow {
|
||||
return 0, ErrGasUintOverflow
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import (
|
|||
"github.com/XinFinOrg/XDPoSChain/core/asm"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/tracing"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/vm/program"
|
||||
|
|
@ -801,3 +802,83 @@ func BenchmarkTracerStepVsCallFrame(b *testing.B) {
|
|||
benchmarkNonModifyingCode(10000000, code, "tracer-step-10M", stepTracer, b)
|
||||
benchmarkNonModifyingCode(10000000, code, "tracer-call-frame-10M", callFrameTracer, b)
|
||||
}
|
||||
|
||||
// TestDelegatedAccountAccessCost tests that calling an account with an EIP-7702
|
||||
// delegation designator incurs the correct amount of gas based on the tracer.
|
||||
func TestDelegatedAccountAccessCost(t *testing.T) {
|
||||
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||
statedb.SetCode(common.HexToAddress("0xff"), types.AddressToDelegation(common.HexToAddress("0xaa")))
|
||||
statedb.SetCode(common.HexToAddress("0xaa"), program.New().Return(0, 0).Bytes())
|
||||
|
||||
for i, tc := range []struct {
|
||||
code []byte
|
||||
step int
|
||||
want uint64
|
||||
}{
|
||||
{ // CALL(0xff)
|
||||
code: []byte{
|
||||
byte(vm.PUSH1), 0x0,
|
||||
byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1),
|
||||
byte(vm.PUSH1), 0xff, byte(vm.DUP1), byte(vm.CALL), byte(vm.POP),
|
||||
},
|
||||
step: 7,
|
||||
want: 5455,
|
||||
},
|
||||
{ // CALLCODE(0xff)
|
||||
code: []byte{
|
||||
byte(vm.PUSH1), 0x0,
|
||||
byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1),
|
||||
byte(vm.PUSH1), 0xff, byte(vm.DUP1), byte(vm.CALLCODE), byte(vm.POP),
|
||||
},
|
||||
step: 7,
|
||||
want: 5455,
|
||||
},
|
||||
{ // DELEGATECALL(0xff)
|
||||
code: []byte{
|
||||
byte(vm.PUSH1), 0x0,
|
||||
byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1),
|
||||
byte(vm.PUSH1), 0xff, byte(vm.DUP1), byte(vm.DELEGATECALL), byte(vm.POP),
|
||||
},
|
||||
step: 6,
|
||||
want: 5455,
|
||||
},
|
||||
{ // STATICCALL(0xff)
|
||||
code: []byte{
|
||||
byte(vm.PUSH1), 0x0,
|
||||
byte(vm.DUP1), byte(vm.DUP1), byte(vm.DUP1),
|
||||
byte(vm.PUSH1), 0xff, byte(vm.DUP1), byte(vm.STATICCALL), byte(vm.POP),
|
||||
},
|
||||
step: 6,
|
||||
want: 5455,
|
||||
},
|
||||
{ // SELFDESTRUCT(0xff): should not be affected by resolution
|
||||
code: []byte{
|
||||
byte(vm.PUSH1), 0xff, byte(vm.SELFDESTRUCT),
|
||||
},
|
||||
step: 1,
|
||||
want: 7600,
|
||||
},
|
||||
} {
|
||||
var step = 0
|
||||
var have = uint64(0)
|
||||
Execute(tc.code, nil, &Config{
|
||||
ChainConfig: params.MergedTestChainConfig,
|
||||
State: statedb,
|
||||
EVMConfig: vm.Config{
|
||||
Tracer: &tracing.Hooks{
|
||||
OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
// Uncomment to investigate failures:
|
||||
t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost)
|
||||
if step == tc.step {
|
||||
have = cost
|
||||
}
|
||||
step++
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if want := tc.want; have != want {
|
||||
t.Fatalf("testcase %d, gas report wrong, step %d, have %d want %d", i, tc.step, have, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
80
eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json
vendored
Normal file
80
eth/tracers/internal/tracetest/testdata/prestate_tracer/setcode_tx.json
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
{
|
||||
"genesis": {
|
||||
"baseFeePerGas": "7",
|
||||
"blobGasUsed": "0",
|
||||
"difficulty": "0",
|
||||
"excessBlobGas": "36306944",
|
||||
"extraData": "0xd983010e00846765746888676f312e32312e308664617277696e",
|
||||
"gasLimit": "15639172",
|
||||
"hash": "0xc682259fda061bb9ce8ccb491d5b2d436cb73daf04e1025dd116d045ce4ad28c",
|
||||
"miner": "0x0000000000000000000000000000000000000000",
|
||||
"mixHash": "0xae1a5ba939a4c9ac38aabeff361169fb55a6fc2c9511457e0be6eff9514faec0",
|
||||
"nonce": "0x0000000000000000",
|
||||
"number": "315",
|
||||
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"stateRoot": "0x577f42ab21ccfd946511c57869ace0bdf7c217c36f02b7cd3459df0ed1cffc1a",
|
||||
"timestamp": "1709626771",
|
||||
"withdrawals": [],
|
||||
"withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
"alloc": {
|
||||
"0x0000000000000000000000000000000000000000": {
|
||||
"balance": "0x272e0528"
|
||||
},
|
||||
"0x000000000000000000000000000000000000aaaa": {
|
||||
"code": "0x6000600060006000600173703c4b2bd70c169f5717101caee543299fc946c75af1",
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x000000000000000000000000000000000000bbbb": {
|
||||
"code": "0x6042604255",
|
||||
"balance": "0x0"
|
||||
},
|
||||
"0x703c4b2bd70c169f5717101caee543299fc946c7": {
|
||||
"balance": "0xde0b6b3a7640000"
|
||||
},
|
||||
"0x71562b71999873db5b286df957af199ec94617f7": {
|
||||
"balance": "0xde0b6b3a7640000"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"chainId": 1337,
|
||||
"homesteadBlock": 0,
|
||||
"eip150Block": 0,
|
||||
"eip155Block": 0,
|
||||
"eip158Block": 0,
|
||||
"byzantiumBlock": 0,
|
||||
"constantinopleBlock": 0,
|
||||
"petersburgBlock": 0,
|
||||
"istanbulBlock": 0,
|
||||
"muirGlacierBlock": 0,
|
||||
"berlinBlock": 0,
|
||||
"londonBlock": 0,
|
||||
"eip1559Block": 0,
|
||||
"cancunBlock": 0,
|
||||
"pragueBlock": 0,
|
||||
"terminalTotalDifficulty": 0
|
||||
}
|
||||
},
|
||||
"context": {
|
||||
"number": "316",
|
||||
"difficulty": "0",
|
||||
"timestamp": "1709626785",
|
||||
"gasLimit": "15654443",
|
||||
"miner": "0x0000000000000000000000000000000000000000",
|
||||
"baseFeePerGas": "7"
|
||||
},
|
||||
"input": "04f90126820539800285012a05f2008307a1209471562b71999873db5b286df957af199ec94617f78080c0f8baf85c82053994000000000000000000000000000000000000aaaa0101a07ed17af7d2d2b9ba7d797a202125bf505b9a0f962a67b3b61b56783d8faf7461a001b73b6e586edc706dce6c074eaec28692fa6359fb3446a2442f36777e1c0669f85a8094000000000000000000000000000000000000bbbb8001a05011890f198f0356a887b0779bde5afa1ed04e6acb1e3f37f8f18c7b6f521b98a056c3fa3456b103f3ef4a0acb4b647b9cab9ec4bc68fbcdf1e10b49fb2bcbcf6101a0167b0ecfc343a497095c22ee4270d3cc3b971cc3599fc73bbff727e0d2ed432da01c003c72306807492bf1150e39b2f79da23b49a4e83eb6e9209ae30d3572368f",
|
||||
"result": {
|
||||
"0x0000000000000000000000000000000000000000": {
|
||||
"balance": "0x272e0528"
|
||||
},
|
||||
"0x703c4b2bd70c169f5717101caee543299fc946c7": {
|
||||
"balance": "0xde0b6b3a7640000",
|
||||
"storage": {
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000042": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
},
|
||||
"0x71562b71999873db5b286df957af199ec94617f7": {
|
||||
"balance": "0xde0b6b3a7640000"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -159,6 +159,15 @@ func (t *prestateTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction
|
|||
t.lookupAccount(from)
|
||||
t.lookupAccount(t.to)
|
||||
t.lookupAccount(env.Coinbase)
|
||||
|
||||
// Add accounts with authorizations to the prestate before they get applied.
|
||||
for _, auth := range tx.AuthList() {
|
||||
addr, err := auth.Authority()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
t.lookupAccount(addr)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *prestateTracer) OnTxEnd(receipt *types.Receipt, err error) {
|
||||
|
|
|
|||
|
|
@ -1654,26 +1654,27 @@ func (api *BlockChainAPI) rpcOutputBlockSigners(b *types.Block, ctx context.Cont
|
|||
|
||||
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
|
||||
type RPCTransaction struct {
|
||||
BlockHash *common.Hash `json:"blockHash"`
|
||||
BlockNumber *hexutil.Big `json:"blockNumber"`
|
||||
From common.Address `json:"from"`
|
||||
Gas hexutil.Uint64 `json:"gas"`
|
||||
GasPrice *hexutil.Big `json:"gasPrice"`
|
||||
GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
|
||||
GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
|
||||
Hash common.Hash `json:"hash"`
|
||||
Input hexutil.Bytes `json:"input"`
|
||||
Nonce hexutil.Uint64 `json:"nonce"`
|
||||
To *common.Address `json:"to"`
|
||||
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
|
||||
Value *hexutil.Big `json:"value"`
|
||||
Type hexutil.Uint64 `json:"type"`
|
||||
Accesses *types.AccessList `json:"accessList,omitempty"`
|
||||
ChainID *hexutil.Big `json:"chainId,omitempty"`
|
||||
V *hexutil.Big `json:"v"`
|
||||
R *hexutil.Big `json:"r"`
|
||||
S *hexutil.Big `json:"s"`
|
||||
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
|
||||
BlockHash *common.Hash `json:"blockHash"`
|
||||
BlockNumber *hexutil.Big `json:"blockNumber"`
|
||||
From common.Address `json:"from"`
|
||||
Gas hexutil.Uint64 `json:"gas"`
|
||||
GasPrice *hexutil.Big `json:"gasPrice"`
|
||||
GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
|
||||
GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
|
||||
Hash common.Hash `json:"hash"`
|
||||
Input hexutil.Bytes `json:"input"`
|
||||
Nonce hexutil.Uint64 `json:"nonce"`
|
||||
To *common.Address `json:"to"`
|
||||
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
|
||||
Value *hexutil.Big `json:"value"`
|
||||
Type hexutil.Uint64 `json:"type"`
|
||||
Accesses *types.AccessList `json:"accessList,omitempty"`
|
||||
ChainID *hexutil.Big `json:"chainId,omitempty"`
|
||||
AuthorizationList []types.Authorization `json:"authorizationList,omitempty"`
|
||||
V *hexutil.Big `json:"v"`
|
||||
R *hexutil.Big `json:"r"`
|
||||
S *hexutil.Big `json:"s"`
|
||||
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
|
||||
}
|
||||
|
||||
// newRPCTransaction returns a transaction that will serialize to the RPC
|
||||
|
|
@ -1730,6 +1731,22 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
|
|||
} else {
|
||||
result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
|
||||
}
|
||||
|
||||
case types.SetCodeTxType:
|
||||
al := tx.AccessList()
|
||||
yparity := hexutil.Uint64(v.Sign())
|
||||
result.Accesses = &al
|
||||
result.ChainID = (*hexutil.Big)(tx.ChainId())
|
||||
result.YParity = &yparity
|
||||
result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
|
||||
result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
|
||||
// if the transaction has been mined, compute the effective gas price
|
||||
if baseFee != nil && blockHash != (common.Hash{}) {
|
||||
result.GasPrice = (*hexutil.Big)(effectiveGasPrice(tx, baseFee))
|
||||
} else {
|
||||
result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
|
||||
}
|
||||
result.AuthorizationList = tx.AuthList()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import (
|
|||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/log"
|
||||
"github.com/XinFinOrg/XDPoSChain/rpc"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// TransactionArgs represents the arguments to construct a new transaction
|
||||
|
|
@ -54,6 +55,9 @@ type TransactionArgs struct {
|
|||
// Introduced by AccessListTxType transaction.
|
||||
AccessList *types.AccessList `json:"accessList,omitempty"`
|
||||
ChainID *hexutil.Big `json:"chainId,omitempty"`
|
||||
|
||||
// For SetCodeTxType
|
||||
AuthorizationList []types.Authorization `json:"authorizationList"`
|
||||
}
|
||||
|
||||
// from retrieves the transaction sender address.
|
||||
|
|
@ -93,8 +97,15 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas
|
|||
if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
|
||||
return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`)
|
||||
}
|
||||
if args.To == nil && len(args.data()) == 0 {
|
||||
return errors.New(`contract creation without any data provided`)
|
||||
|
||||
// create check
|
||||
if args.To == nil {
|
||||
if args.AuthorizationList != nil {
|
||||
return errors.New("eip7702 set code transaction requires a destination address")
|
||||
}
|
||||
if len(args.data()) == 0 {
|
||||
return errors.New(`contract creation without any data provided`)
|
||||
}
|
||||
}
|
||||
|
||||
if args.Gas == nil {
|
||||
|
|
@ -343,6 +354,8 @@ func (args *TransactionArgs) ToMessage(b AccountBackend, baseFee *big.Int, skipN
|
|||
func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction {
|
||||
usedType := types.LegacyTxType
|
||||
switch {
|
||||
case args.AuthorizationList != nil || defaultType == types.SetCodeTxType:
|
||||
usedType = types.SetCodeTxType
|
||||
case args.MaxFeePerGas != nil || defaultType == types.DynamicFeeTxType:
|
||||
usedType = types.DynamicFeeTxType
|
||||
case args.AccessList != nil || defaultType == types.AccessListTxType:
|
||||
|
|
@ -354,6 +367,28 @@ func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction {
|
|||
}
|
||||
var data types.TxData
|
||||
switch usedType {
|
||||
case types.SetCodeTxType:
|
||||
al := types.AccessList{}
|
||||
if args.AccessList != nil {
|
||||
al = *args.AccessList
|
||||
}
|
||||
authList := []types.Authorization{}
|
||||
if args.AuthorizationList != nil {
|
||||
authList = args.AuthorizationList
|
||||
}
|
||||
data = &types.SetCodeTx{
|
||||
To: *args.To,
|
||||
ChainID: args.ChainID.ToInt().Uint64(),
|
||||
Nonce: uint64(*args.Nonce),
|
||||
Gas: uint64(*args.Gas),
|
||||
GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)),
|
||||
GasTipCap: uint256.MustFromBig((*big.Int)(args.MaxPriorityFeePerGas)),
|
||||
Value: uint256.MustFromBig((*big.Int)(args.Value)),
|
||||
Data: args.data(),
|
||||
AccessList: al,
|
||||
AuthList: authList,
|
||||
}
|
||||
|
||||
case types.DynamicFeeTxType:
|
||||
al := types.AccessList{}
|
||||
if args.AccessList != nil {
|
||||
|
|
@ -370,6 +405,7 @@ func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction {
|
|||
Data: args.data(),
|
||||
AccessList: al,
|
||||
}
|
||||
|
||||
case types.AccessListTxType:
|
||||
data = &types.AccessListTx{
|
||||
To: args.To,
|
||||
|
|
@ -381,6 +417,7 @@ func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction {
|
|||
Data: args.data(),
|
||||
AccessList: *args.AccessList,
|
||||
}
|
||||
|
||||
default:
|
||||
data = &types.LegacyTx{
|
||||
To: args.To,
|
||||
|
|
|
|||
|
|
@ -434,6 +434,31 @@ var (
|
|||
Clique: nil,
|
||||
XDPoS: nil,
|
||||
}
|
||||
|
||||
// MergedTestChainConfig contains every protocol change (EIPs) introduced
|
||||
// and accepted by the Ethereum core developers for testing purposes.
|
||||
MergedTestChainConfig = &ChainConfig{
|
||||
ChainID: big.NewInt(1),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: false,
|
||||
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),
|
||||
ShanghaiBlock: big.NewInt(0),
|
||||
Eip1559Block: big.NewInt(0),
|
||||
CancunBlock: big.NewInt(0),
|
||||
PragueBlock: big.NewInt(0),
|
||||
Ethash: new(EthashConfig),
|
||||
Clique: nil,
|
||||
XDPoS: nil,
|
||||
}
|
||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||
)
|
||||
|
||||
|
|
@ -982,9 +1007,11 @@ func (c *ChainConfig) IsTIPIncreaseMasternodes(num *big.Int) bool {
|
|||
func (c *ChainConfig) IsTIPNoHalvingMNReward(num *big.Int) bool {
|
||||
return isForked(common.TIPNoHalvingMNReward, num)
|
||||
}
|
||||
|
||||
func (c *ChainConfig) IsTIPXDCX(num *big.Int) bool {
|
||||
return isForked(common.TIPXDCX, num)
|
||||
}
|
||||
|
||||
func (c *ChainConfig) IsTIPXDCXMiner(num *big.Int) bool {
|
||||
return isForked(common.TIPXDCX, num) && !isForked(common.TIPXDCXMinerDisable, num)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,8 +65,9 @@ const (
|
|||
SuicideRefundGas uint64 = 24000 // Refunded following a suicide operation.
|
||||
MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
|
||||
|
||||
TxAccessListAddressGas uint64 = 2400 // Per address specified in EIP 2930 access list
|
||||
TxAccessListStorageKeyGas uint64 = 1900 // Per storage key specified in EIP 2930 access list
|
||||
TxAccessListAddressGas uint64 = 2400 // Per address specified in EIP 2930 access list
|
||||
TxAccessListStorageKeyGas uint64 = 1900 // Per storage key specified in EIP 2930 access list
|
||||
TxAuthTupleGas uint64 = 12500 // Per auth tuple code specified in EIP-7702
|
||||
|
||||
TxDataNonZeroGas uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
|
||||
|
||||
|
|
|
|||
74
tests/gen_stauthorization.go
Normal file
74
tests/gen_stauthorization.go
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||
|
||||
package tests
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/math"
|
||||
)
|
||||
|
||||
var _ = (*stAuthorizationMarshaling)(nil)
|
||||
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (s stAuthorization) MarshalJSON() ([]byte, error) {
|
||||
type stAuthorization struct {
|
||||
ChainID math.HexOrDecimal64
|
||||
Address common.Address `json:"address" gencodec:"required"`
|
||||
Nonce math.HexOrDecimal64 `json:"nonce" gencodec:"required"`
|
||||
V math.HexOrDecimal64 `json:"v" gencodec:"required"`
|
||||
R *math.HexOrDecimal256 `json:"r" gencodec:"required"`
|
||||
S *math.HexOrDecimal256 `json:"s" gencodec:"required"`
|
||||
}
|
||||
var enc stAuthorization
|
||||
enc.ChainID = math.HexOrDecimal64(s.ChainID)
|
||||
enc.Address = s.Address
|
||||
enc.Nonce = math.HexOrDecimal64(s.Nonce)
|
||||
enc.V = math.HexOrDecimal64(s.V)
|
||||
enc.R = (*math.HexOrDecimal256)(s.R)
|
||||
enc.S = (*math.HexOrDecimal256)(s.S)
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (s *stAuthorization) UnmarshalJSON(input []byte) error {
|
||||
type stAuthorization struct {
|
||||
ChainID *math.HexOrDecimal64
|
||||
Address *common.Address `json:"address" gencodec:"required"`
|
||||
Nonce *math.HexOrDecimal64 `json:"nonce" gencodec:"required"`
|
||||
V *math.HexOrDecimal64 `json:"v" gencodec:"required"`
|
||||
R *math.HexOrDecimal256 `json:"r" gencodec:"required"`
|
||||
S *math.HexOrDecimal256 `json:"s" gencodec:"required"`
|
||||
}
|
||||
var dec stAuthorization
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
if dec.ChainID != nil {
|
||||
s.ChainID = uint64(*dec.ChainID)
|
||||
}
|
||||
if dec.Address == nil {
|
||||
return errors.New("missing required field 'address' for stAuthorization")
|
||||
}
|
||||
s.Address = *dec.Address
|
||||
if dec.Nonce == nil {
|
||||
return errors.New("missing required field 'nonce' for stAuthorization")
|
||||
}
|
||||
s.Nonce = uint64(*dec.Nonce)
|
||||
if dec.V == nil {
|
||||
return errors.New("missing required field 'v' for stAuthorization")
|
||||
}
|
||||
s.V = uint8(*dec.V)
|
||||
if dec.R == nil {
|
||||
return errors.New("missing required field 'r' for stAuthorization")
|
||||
}
|
||||
s.R = (*big.Int)(dec.R)
|
||||
if dec.S == nil {
|
||||
return errors.New("missing required field 's' for stAuthorization")
|
||||
}
|
||||
s.S = (*big.Int)(dec.S)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ func (s stTransaction) MarshalJSON() ([]byte, error) {
|
|||
GasLimit []math.HexOrDecimal64 `json:"gasLimit"`
|
||||
Value []string `json:"value"`
|
||||
PrivateKey hexutil.Bytes `json:"secretKey"`
|
||||
AuthorizationList []*stAuthorization `json:"authorizationList,omitempty"`
|
||||
}
|
||||
var enc stTransaction
|
||||
enc.GasPrice = (*math.HexOrDecimal256)(s.GasPrice)
|
||||
|
|
@ -43,6 +44,7 @@ func (s stTransaction) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
enc.Value = s.Value
|
||||
enc.PrivateKey = s.PrivateKey
|
||||
enc.AuthorizationList = s.AuthorizationList
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
|
|
@ -59,6 +61,7 @@ func (s *stTransaction) UnmarshalJSON(input []byte) error {
|
|||
GasLimit []math.HexOrDecimal64 `json:"gasLimit"`
|
||||
Value []string `json:"value"`
|
||||
PrivateKey *hexutil.Bytes `json:"secretKey"`
|
||||
AuthorizationList []*stAuthorization `json:"authorizationList,omitempty"`
|
||||
}
|
||||
var dec stTransaction
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
|
|
@ -97,5 +100,8 @@ func (s *stTransaction) UnmarshalJSON(input []byte) error {
|
|||
if dec.PrivateKey != nil {
|
||||
s.PrivateKey = *dec.PrivateKey
|
||||
}
|
||||
if dec.AuthorizationList != nil {
|
||||
s.AuthorizationList = dec.AuthorizationList
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import (
|
|||
"github.com/XinFinOrg/XDPoSChain/ethdb"
|
||||
"github.com/XinFinOrg/XDPoSChain/params"
|
||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||
"github.com/holiman/uint256"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
|
|
@ -107,6 +108,7 @@ type stTransaction struct {
|
|||
GasLimit []uint64 `json:"gasLimit"`
|
||||
Value []string `json:"value"`
|
||||
PrivateKey []byte `json:"secretKey"`
|
||||
AuthorizationList []*stAuthorization `json:"authorizationList,omitempty"`
|
||||
}
|
||||
|
||||
type stTransactionMarshaling struct {
|
||||
|
|
@ -118,6 +120,27 @@ type stTransactionMarshaling struct {
|
|||
PrivateKey hexutil.Bytes
|
||||
}
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type stAuthorization -field-override stAuthorizationMarshaling -out gen_stauthorization.go
|
||||
|
||||
// Authorization is an authorization from an account to deploy code at its address.
|
||||
type stAuthorization struct {
|
||||
ChainID uint64
|
||||
Address common.Address `json:"address" gencodec:"required"`
|
||||
Nonce uint64 `json:"nonce" gencodec:"required"`
|
||||
V uint8 `json:"v" gencodec:"required"`
|
||||
R *big.Int `json:"r" gencodec:"required"`
|
||||
S *big.Int `json:"s" gencodec:"required"`
|
||||
}
|
||||
|
||||
// field type overrides for gencodec
|
||||
type stAuthorizationMarshaling struct {
|
||||
ChainID math.HexOrDecimal64
|
||||
Nonce math.HexOrDecimal64
|
||||
V math.HexOrDecimal64
|
||||
R *math.HexOrDecimal256
|
||||
S *math.HexOrDecimal256
|
||||
}
|
||||
|
||||
// Subtests returns all valid subtests of the test.
|
||||
func (t *StateTest) Subtests() []StateSubtest {
|
||||
var sub []StateSubtest
|
||||
|
|
@ -284,6 +307,20 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Mess
|
|||
if gasPrice == nil {
|
||||
return nil, errors.New("no gas price provided")
|
||||
}
|
||||
var authList []types.Authorization
|
||||
if tx.AuthorizationList != nil {
|
||||
authList = make([]types.Authorization, len(tx.AuthorizationList))
|
||||
for i, auth := range tx.AuthorizationList {
|
||||
authList[i] = types.Authorization{
|
||||
ChainID: auth.ChainID,
|
||||
Address: auth.Address,
|
||||
Nonce: auth.Nonce,
|
||||
V: auth.V,
|
||||
R: *uint256.MustFromBig(auth.R),
|
||||
S: *uint256.MustFromBig(auth.S),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg := &core.Message{
|
||||
From: from,
|
||||
|
|
@ -296,6 +333,7 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Mess
|
|||
GasTipCap: tx.MaxPriorityFeePerGas,
|
||||
Data: data,
|
||||
AccessList: accessList,
|
||||
AuthList: authList,
|
||||
SkipNonceChecks: false,
|
||||
SkipFromEOACheck: false,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue