mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 19:30:44 +00:00
core: remove duplication
This commit is contained in:
parent
478fe9e825
commit
407839baec
3 changed files with 52 additions and 279 deletions
|
|
@ -463,56 +463,6 @@ func TestEIP2780RecipientOOG(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestEIP2780AuthOOG pins the atomic authorization charge point: a later
|
|
||||||
// authorization OOG reverts an earlier successful authorization too.
|
|
||||||
func TestEIP2780AuthOOG(t *testing.T) {
|
|
||||||
a0, authority0 := signAuth(t, authKeyA, delegate8037, 0)
|
|
||||||
key, _ := crypto.GenerateKey()
|
|
||||||
a1, err := types.SignSetCode(key, types.SetCodeAuthorization{
|
|
||||||
ChainID: *uint256.MustFromBig(cfg8037.ChainID), Address: delegate8037, Nonce: 0,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
authority1 := crypto.PubkeyToAddress(key.PublicKey)
|
|
||||||
to := common.HexToAddress("0xe0a0000000000000000000000000000000000009")
|
|
||||||
intrinsic := params.TxBaseCost2780 + params.ColdAccountAccessAmsterdam + 2*params.RegularPerAuthBaseCost
|
|
||||||
gas := intrinsic + params.AccountWriteAmsterdam + authWorstState
|
|
||||||
sdb := mkState(senderAlloc(types.GenesisAlloc{to: {Balance: big.NewInt(1)}}))
|
|
||||||
res, gp, err := applyMsg(t, sdb, setCodeTxGas(0, to, 0, gas, []types.SetCodeAuthorization{a0, a1}))
|
|
||||||
if err != nil || res.Err != vm.ErrOutOfGas {
|
|
||||||
t.Fatalf("result=%v err=%v, want included OOG", res, err)
|
|
||||||
}
|
|
||||||
for _, authority := range []common.Address{authority0, authority1} {
|
|
||||||
if len(sdb.GetCode(authority)) != 0 || sdb.GetNonce(authority) != 0 {
|
|
||||||
t.Fatalf("authority %x persisted after authorization OOG", authority)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if gp.cumulativeState != 0 || gp.cumulativeRegular != gas {
|
|
||||||
t.Fatalf("gas = <%d,%d>, want <%d,0>", gp.cumulativeRegular, gp.cumulativeState, gas)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestEIP2780AuthRevert distinguishes an EVM REVERT from a pre-frame OOG:
|
|
||||||
// state paid by a successful authorization precedes the frame and persists.
|
|
||||||
func TestEIP2780AuthRevert(t *testing.T) {
|
|
||||||
auth, authority := signAuth(t, authKeyA, delegate8037, 0)
|
|
||||||
reverter := common.HexToAddress("0xbad0000000000000000000000000000000000003")
|
|
||||||
sdb := mkState(senderAlloc(types.GenesisAlloc{
|
|
||||||
reverter: {Code: []byte{0x60, 0x00, 0x60, 0x00, 0xfd}},
|
|
||||||
}))
|
|
||||||
res, gp, err := applyMsg(t, sdb, setCodeTxGas(0, reverter, 0, 1_000_000, []types.SetCodeAuthorization{auth}))
|
|
||||||
if err != nil || res.Err != vm.ErrExecutionReverted {
|
|
||||||
t.Fatalf("result=%v err=%v, want execution revert", res, err)
|
|
||||||
}
|
|
||||||
if len(sdb.GetCode(authority)) == 0 || sdb.GetNonce(authority) != 1 {
|
|
||||||
t.Fatalf("authorization not retained after revert: code=%x nonce=%d", sdb.GetCode(authority), sdb.GetNonce(authority))
|
|
||||||
}
|
|
||||||
if gp.cumulativeState != authWorstState {
|
|
||||||
t.Fatalf("state gas = %d, want %d", gp.cumulativeState, authWorstState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestEIP2780SelfTransferDelegated verifies that a self-transfer incurs no
|
// TestEIP2780SelfTransferDelegated verifies that a self-transfer incurs no
|
||||||
// recipient touch or value charges, while resolving the sender's own
|
// recipient touch or value charges, while resolving the sender's own
|
||||||
// delegation is still paid for.
|
// delegation is still paid for.
|
||||||
|
|
@ -648,72 +598,19 @@ func TestEIP2780RecipientRefill(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestEIP2780ValueEffects checks the observable value-transfer behavior along
|
|
||||||
// with the decomposition's special treatment of self and creation transfers.
|
|
||||||
func TestEIP2780ValueEffects(t *testing.T) {
|
|
||||||
recipient := common.HexToAddress("0xbeef000000000000000000000000000000000006")
|
|
||||||
sdb := mkState(senderAlloc(nil))
|
|
||||||
before := sdb.GetBalance(senderAddr).ToBig()
|
|
||||||
tx := callTx(0, recipient, 7, 300_000, nil)
|
|
||||||
res, _, err := applyMsg(t, sdb, tx)
|
|
||||||
if err != nil || res.Err != nil {
|
|
||||||
t.Fatalf("result=%v err=%v", res, err)
|
|
||||||
}
|
|
||||||
if got := sdb.GetBalance(recipient).ToBig(); got.Cmp(big.NewInt(7)) != 0 {
|
|
||||||
t.Fatalf("recipient balance = %v, want 7", got)
|
|
||||||
}
|
|
||||||
if got := sdb.GetBalance(senderAddr).ToBig(); got.Cmp(new(big.Int).Sub(before, big.NewInt(7))) != 0 {
|
|
||||||
t.Fatalf("sender balance = %v, want value transfer", got)
|
|
||||||
}
|
|
||||||
logs := sdb.GetLogs(common.Hash{}, 0, common.Hash{}, 0)
|
|
||||||
if len(logs) != 1 || logs[0].Topics[0] != params.EthTransferLogEvent {
|
|
||||||
t.Fatalf("logs = %+v, want one EIP-7708 transfer", logs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A self transfer is not a value move and emits no transfer log.
|
|
||||||
sdb = mkState(senderAlloc(nil))
|
|
||||||
before = sdb.GetBalance(senderAddr).ToBig()
|
|
||||||
tx = callTx(0, senderAddr, 7, 100_000, nil)
|
|
||||||
res, _, err = applyMsg(t, sdb, tx)
|
|
||||||
if err != nil || res.Err != nil {
|
|
||||||
t.Fatalf("self result=%v err=%v", res, err)
|
|
||||||
}
|
|
||||||
logs = sdb.GetLogs(common.Hash{}, 0, common.Hash{}, 0)
|
|
||||||
if sdb.GetBalance(senderAddr).Cmp(uint256.MustFromBig(before)) != 0 || len(logs) != 0 {
|
|
||||||
t.Fatalf("self transfer changed balance or emitted logs: balance=%v logs=%+v", sdb.GetBalance(senderAddr), logs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestEIP2780Coinbase keeps the intrinsic recipient charge separate from the
|
// TestEIP2780Coinbase keeps the intrinsic recipient charge separate from the
|
||||||
// runtime warmth of the coinbase account.
|
// runtime warmth of the coinbase account: calling the coinbase directly is
|
||||||
|
// still charged at the cold rate. The warm rate for a coinbase delegation
|
||||||
|
// target is covered by TestEIP2780DelegationWarmth.
|
||||||
func TestEIP2780Coinbase(t *testing.T) {
|
func TestEIP2780Coinbase(t *testing.T) {
|
||||||
const (
|
|
||||||
base = params.TxBaseCost2780
|
|
||||||
cold = params.ColdAccountAccessAmsterdam
|
|
||||||
warm = params.WarmAccountAccessAmsterdam
|
|
||||||
)
|
|
||||||
coinbase := common.HexToAddress("0xc01ba5e000000000000000000000000000000001")
|
coinbase := common.HexToAddress("0xc01ba5e000000000000000000000000000000001")
|
||||||
t.Run("recipient", func(t *testing.T) {
|
|
||||||
res, gp, err := applyMsgCoinbase(t, mkState(senderAlloc(nil)), callTx(0, coinbase, 0, 100_000, nil), coinbase)
|
res, gp, err := applyMsgCoinbase(t, mkState(senderAlloc(nil)), callTx(0, coinbase, 0, 100_000, nil), coinbase)
|
||||||
if err != nil || res.Err != nil {
|
if err != nil || res.Err != nil {
|
||||||
t.Fatalf("result=%v err=%v", res, err)
|
t.Fatalf("result=%v err=%v", res, err)
|
||||||
}
|
}
|
||||||
if gp.cumulativeRegular != base+cold {
|
if want := params.TxBaseCost2780 + params.ColdAccountAccessAmsterdam; gp.cumulativeRegular != want {
|
||||||
t.Fatalf("regular gas = %d, want %d", gp.cumulativeRegular, base+cold)
|
t.Fatalf("regular gas = %d, want %d", gp.cumulativeRegular, want)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
t.Run("target", func(t *testing.T) {
|
|
||||||
delegated := common.HexToAddress("0xde1e000000000000000000000000000000000007")
|
|
||||||
res, gp, err := applyMsgCoinbase(t, mkState(senderAlloc(types.GenesisAlloc{
|
|
||||||
delegated: {Code: types.AddressToDelegation(coinbase)},
|
|
||||||
})), callTx(0, delegated, 0, 100_000, nil), coinbase)
|
|
||||||
if err != nil || res.Err != nil {
|
|
||||||
t.Fatalf("result=%v err=%v", res, err)
|
|
||||||
}
|
|
||||||
if gp.cumulativeRegular != base+cold+warm {
|
|
||||||
t.Fatalf("regular gas = %d, want %d", gp.cumulativeRegular, base+cold+warm)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestEIP2780DelegationWarmth adds the special targets which are warm before
|
// TestEIP2780DelegationWarmth adds the special targets which are warm before
|
||||||
|
|
|
||||||
|
|
@ -276,24 +276,6 @@ func TestBALEmptyBlockExcludesCoinbase(t *testing.T) {
|
||||||
assertAbsent(t, b, coinbase)
|
assertAbsent(t, b, coinbase)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestBALCoinbaseTipCapturesBalance: positive priority fee credits coinbase
|
|
||||||
// and the balance change appears in the BAL.
|
|
||||||
func TestBALCoinbaseTipCapturesBalance(t *testing.T) {
|
|
||||||
coinbase := common.Address{0xc0}
|
|
||||||
to := common.HexToAddress("0xabba")
|
|
||||||
env := newBALTestEnv(nil)
|
|
||||||
|
|
||||||
b, _ := env.run(t, func(g *BlockGen) {
|
|
||||||
g.SetCoinbase(coinbase)
|
|
||||||
g.AddTx(env.tx(0, &to, big.NewInt(0), params.TxGas, 2 /* gwei tip */, nil))
|
|
||||||
})
|
|
||||||
|
|
||||||
cb := assertPresent(t, b, coinbase)
|
|
||||||
if len(cb.BalanceChanges) == 0 || cb.BalanceChanges[0].PostBalance.Sign() == 0 {
|
|
||||||
t.Fatalf("coinbase missing positive balance change: %+v", cb.BalanceChanges)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestBALCoinbasePerTxBalance checks that fee-recipient balances are recorded
|
// TestBALCoinbasePerTxBalance checks that fee-recipient balances are recorded
|
||||||
// after each transaction, rather than only once at the end of the block.
|
// after each transaction, rather than only once at the end of the block.
|
||||||
func TestBALCoinbasePerTxBalance(t *testing.T) {
|
func TestBALCoinbasePerTxBalance(t *testing.T) {
|
||||||
|
|
@ -718,28 +700,6 @@ func TestBALDelegationTargetOOG(t *testing.T) {
|
||||||
|
|
||||||
// ============================== Storage inclusion ==============================
|
// ============================== Storage inclusion ==============================
|
||||||
|
|
||||||
// TestBALStorageWriteRecorded: SSTORE places the slot in storage_changes and
|
|
||||||
// keeps it out of storage_reads.
|
|
||||||
func TestBALStorageWriteRecorded(t *testing.T) {
|
|
||||||
contract := common.HexToAddress("0xc1")
|
|
||||||
slot := common.BigToHash(big.NewInt(0x01))
|
|
||||||
// PUSH1 0x42 PUSH1 0x01 SSTORE STOP
|
|
||||||
code := []byte{0x60, 0x42, 0x60, 0x01, 0x55, 0x00}
|
|
||||||
env := newBALTestEnv(types.GenesisAlloc{contract: {Code: code, Balance: common.Big0}})
|
|
||||||
|
|
||||||
b, _ := env.run(t, func(g *BlockGen) {
|
|
||||||
g.AddTx(env.tx(0, &contract, big.NewInt(0), 1_000_000, 0, nil))
|
|
||||||
})
|
|
||||||
|
|
||||||
aa := assertPresent(t, b, contract)
|
|
||||||
if !hasStorageWrite(b, contract, slot) {
|
|
||||||
t.Fatalf("expected slot 0x01 in storage_changes\n%s", b.PrettyPrint())
|
|
||||||
}
|
|
||||||
if hasSlotIn(aa.StorageReads, slot) {
|
|
||||||
t.Fatalf("slot 0x01 must NOT appear in storage_reads")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestBALStorageSloadOnly: SLOAD without a write puts the slot in storage_reads.
|
// TestBALStorageSloadOnly: SLOAD without a write puts the slot in storage_reads.
|
||||||
func TestBALStorageSloadOnly(t *testing.T) {
|
func TestBALStorageSloadOnly(t *testing.T) {
|
||||||
contract := common.HexToAddress("0xc1")
|
contract := common.HexToAddress("0xc1")
|
||||||
|
|
@ -2128,17 +2088,30 @@ func TestBALDelegatedCallStorage(t *testing.T) {
|
||||||
assertEmpty(t, assertPresent(t, b, implementation))
|
assertEmpty(t, assertPresent(t, b, implementation))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestBALDelegatedDelegateCallStorage checks the other storage context:
|
// TestBALDelegatedCallFamilyStorage checks the storage context of the CALL
|
||||||
// DELEGATECALL to a delegated authority still executes the resolved code
|
// family against a delegated authority: the resolved implementation supplies
|
||||||
// against the original caller's storage.
|
// code only, while the storage read belongs to the executing context — the
|
||||||
func TestBALDelegatedDelegateCallStorage(t *testing.T) {
|
// authority for CALL/STATICCALL, the caller for DELEGATECALL/CALLCODE.
|
||||||
|
func TestBALDelegatedCallFamilyStorage(t *testing.T) {
|
||||||
caller := common.HexToAddress("0xca11")
|
caller := common.HexToAddress("0xca11")
|
||||||
authority := common.HexToAddress("0xa7702")
|
authority := common.HexToAddress("0xa7702")
|
||||||
implementation := common.HexToAddress("0x1a11")
|
implementation := common.HexToAddress("0x1a11")
|
||||||
slot := common.BigToHash(big.NewInt(0x07))
|
slot := common.BigToHash(big.NewInt(0x07))
|
||||||
implCode := []byte{0x60, 0x07, 0x54, 0x50, 0x00} // SLOAD(7), POP, STOP
|
implCode := []byte{0x60, 0x07, 0x54, 0x50, 0x00} // SLOAD(7), POP, STOP
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
op byte
|
||||||
|
readOwner common.Address
|
||||||
|
}{
|
||||||
|
{"call", 0xf1, authority},
|
||||||
|
{"callcode", 0xf2, caller},
|
||||||
|
{"delegatecall", 0xf4, caller},
|
||||||
|
{"staticcall", 0xfa, authority},
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
env := newBALTestEnv(types.GenesisAlloc{
|
env := newBALTestEnv(types.GenesisAlloc{
|
||||||
caller: {Code: makeStubCaller(0xf4 /* DELEGATECALL */, authority), Balance: common.Big0},
|
caller: {Code: makeStubCaller(tc.op, authority), Balance: common.Big0},
|
||||||
authority: {Code: types.AddressToDelegation(implementation), Balance: common.Big0},
|
authority: {Code: types.AddressToDelegation(implementation), Balance: common.Big0},
|
||||||
implementation: {Code: implCode, Balance: common.Big0},
|
implementation: {Code: implCode, Balance: common.Big0},
|
||||||
})
|
})
|
||||||
|
|
@ -2147,65 +2120,18 @@ func TestBALDelegatedDelegateCallStorage(t *testing.T) {
|
||||||
g.AddTx(env.tx(0, &caller, big.NewInt(0), 1_000_000, 0, nil))
|
g.AddTx(env.tx(0, &caller, big.NewInt(0), 1_000_000, 0, nil))
|
||||||
})
|
})
|
||||||
|
|
||||||
callerAccess := assertPresent(t, b, caller)
|
owner := assertPresent(t, b, tc.readOwner)
|
||||||
if !hasSlotIn(callerAccess.StorageReads, slot) {
|
if !hasSlotIn(owner.StorageReads, slot) {
|
||||||
t.Fatalf("delegated DELEGATECALL read must belong to caller\n%s", b.PrettyPrint())
|
t.Fatalf("%s read must belong to %x\n%s", tc.name, tc.readOwner, b.PrettyPrint())
|
||||||
|
}
|
||||||
|
for _, other := range []common.Address{caller, authority} {
|
||||||
|
if other != tc.readOwner {
|
||||||
|
assertEmpty(t, assertPresent(t, b, other))
|
||||||
}
|
}
|
||||||
assertEmpty(t, assertPresent(t, b, authority))
|
|
||||||
assertEmpty(t, assertPresent(t, b, implementation))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestBALDelegatedStaticCallStorage covers STATICCALL's context. It resolves
|
|
||||||
// the authority's implementation code, but SLOAD remains attached to the static
|
|
||||||
// call target's storage.
|
|
||||||
func TestBALDelegatedStaticCallStorage(t *testing.T) {
|
|
||||||
caller := common.HexToAddress("0xca11")
|
|
||||||
authority := common.HexToAddress("0xa7702")
|
|
||||||
implementation := common.HexToAddress("0x1a11")
|
|
||||||
slot := common.BigToHash(big.NewInt(0x07))
|
|
||||||
implCode := []byte{0x60, 0x07, 0x54, 0x50, 0x00} // SLOAD(7), POP, STOP
|
|
||||||
env := newBALTestEnv(types.GenesisAlloc{
|
|
||||||
caller: {Code: makeStubCaller(0xfa /* STATICCALL */, authority), Balance: common.Big0},
|
|
||||||
authority: {Code: types.AddressToDelegation(implementation), Balance: common.Big0},
|
|
||||||
implementation: {Code: implCode, Balance: common.Big0},
|
|
||||||
})
|
|
||||||
|
|
||||||
b, _ := env.run(t, func(g *BlockGen) {
|
|
||||||
g.AddTx(env.tx(0, &caller, big.NewInt(0), 1_000_000, 0, nil))
|
|
||||||
})
|
|
||||||
|
|
||||||
authorityAccess := assertPresent(t, b, authority)
|
|
||||||
if !hasSlotIn(authorityAccess.StorageReads, slot) {
|
|
||||||
t.Fatalf("delegated STATICCALL read must belong to authority\n%s", b.PrettyPrint())
|
|
||||||
}
|
}
|
||||||
assertEmpty(t, assertPresent(t, b, implementation))
|
assertEmpty(t, assertPresent(t, b, implementation))
|
||||||
}
|
|
||||||
|
|
||||||
// TestBALDelegatedCallCodeStorage covers CALLCODE's storage context. As with
|
|
||||||
// DELEGATECALL, the implementation address supplies code but is not the owner
|
|
||||||
// of storage reads.
|
|
||||||
func TestBALDelegatedCallCodeStorage(t *testing.T) {
|
|
||||||
caller := common.HexToAddress("0xca11")
|
|
||||||
authority := common.HexToAddress("0xa7702")
|
|
||||||
implementation := common.HexToAddress("0x1a11")
|
|
||||||
slot := common.BigToHash(big.NewInt(0x07))
|
|
||||||
implCode := []byte{0x60, 0x07, 0x54, 0x50, 0x00} // SLOAD(7), POP, STOP
|
|
||||||
env := newBALTestEnv(types.GenesisAlloc{
|
|
||||||
caller: {Code: makeStubCaller(0xf2 /* CALLCODE */, authority), Balance: common.Big0},
|
|
||||||
authority: {Code: types.AddressToDelegation(implementation), Balance: common.Big0},
|
|
||||||
implementation: {Code: implCode, Balance: common.Big0},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
b, _ := env.run(t, func(g *BlockGen) {
|
|
||||||
g.AddTx(env.tx(0, &caller, big.NewInt(0), 1_000_000, 0, nil))
|
|
||||||
})
|
|
||||||
|
|
||||||
callerAccess := assertPresent(t, b, caller)
|
|
||||||
if !hasSlotIn(callerAccess.StorageReads, slot) {
|
|
||||||
t.Fatalf("delegated CALLCODE read must belong to caller\n%s", b.PrettyPrint())
|
|
||||||
}
|
}
|
||||||
assertEmpty(t, assertPresent(t, b, authority))
|
|
||||||
assertEmpty(t, assertPresent(t, b, implementation))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestBALDelegationOneHop verifies that resolving A -> B does not
|
// TestBALDelegationOneHop verifies that resolving A -> B does not
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,8 @@ import (
|
||||||
// TestEIP8246SelfdestructNoBurn verifies that, once EIP-8246 is active
|
// TestEIP8246SelfdestructNoBurn verifies that, once EIP-8246 is active
|
||||||
// (Amsterdam), a contract that is created and self-destructs to itself within
|
// (Amsterdam), a contract that is created and self-destructs to itself within
|
||||||
// the same transaction keeps its balance instead of burning it: the account
|
// the same transaction keeps its balance instead of burning it: the account
|
||||||
// survives as a balance-only account (no code, zero nonce, balance preserved).
|
// survives as a balance-only account (no code, zero nonce, balance preserved)
|
||||||
|
// whose storage is cleared at transaction finalization.
|
||||||
//
|
//
|
||||||
// https://eips.ethereum.org/EIPS/eip-8246
|
// https://eips.ethereum.org/EIPS/eip-8246
|
||||||
func TestEIP8246SelfdestructNoBurn(t *testing.T) {
|
func TestEIP8246SelfdestructNoBurn(t *testing.T) {
|
||||||
|
|
@ -42,9 +43,11 @@ func TestEIP8246SelfdestructNoBurn(t *testing.T) {
|
||||||
signer = types.LatestSigner(&config)
|
signer = types.LatestSigner(&config)
|
||||||
engine = beacon.New(ethash.NewFaker())
|
engine = beacon.New(ethash.NewFaker())
|
||||||
value = big.NewInt(1_000_000)
|
value = big.NewInt(1_000_000)
|
||||||
// Init code: ADDRESS (0x30) ; SELFDESTRUCT (0xff). The created contract
|
slot = common.BigToHash(big.NewInt(0x05))
|
||||||
// self-destructs to itself during its own creation transaction.
|
// Init code: SSTORE(5, 0x2a); ADDRESS (0x30); SELFDESTRUCT (0xff). The
|
||||||
initcode = common.FromHex("30ff")
|
// created contract stores a value and self-destructs to itself during
|
||||||
|
// its own creation transaction.
|
||||||
|
initcode = []byte{0x60, 0x2a, 0x60, 0x05, 0x55, 0x30, 0xff}
|
||||||
)
|
)
|
||||||
// TODO: drop this hacky Amsterdam config initialization once the final
|
// TODO: drop this hacky Amsterdam config initialization once the final
|
||||||
// Amsterdam config is available (mirrors TestEthTransferLogs).
|
// Amsterdam config is available (mirrors TestEthTransferLogs).
|
||||||
|
|
@ -99,61 +102,8 @@ func TestEIP8246SelfdestructNoBurn(t *testing.T) {
|
||||||
if got := state.GetCodeSize(created); got != 0 {
|
if got := state.GetCodeSize(created); got != 0 {
|
||||||
t.Errorf("created account code size = %d, want 0 (code must be cleared)", got)
|
t.Errorf("created account code size = %d, want 0 (code must be cleared)", got)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// TestEIP8246SelfdestructClearsStorage verifies the other half of the
|
|
||||||
// balance-only-account rule: a same-transaction selfdestruct preserves balance
|
|
||||||
// but clears storage during transaction finalization.
|
|
||||||
func TestEIP8246SelfdestructClearsStorage(t *testing.T) {
|
|
||||||
var (
|
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
|
||||||
sender = crypto.PubkeyToAddress(key.PublicKey)
|
|
||||||
config = *params.MergedTestChainConfig
|
|
||||||
signer = types.LatestSigner(&config)
|
|
||||||
engine = beacon.New(ethash.NewFaker())
|
|
||||||
value = big.NewInt(1_000_000)
|
|
||||||
slot = common.BigToHash(big.NewInt(0x05))
|
|
||||||
stored = common.BigToHash(big.NewInt(0x2a))
|
|
||||||
created = crypto.CreateAddress(sender, 0)
|
|
||||||
)
|
|
||||||
config.AmsterdamTime = new(uint64)
|
|
||||||
gspec := &Genesis{
|
|
||||||
Config: &config,
|
|
||||||
Alloc: types.GenesisAlloc{sender: {Balance: newGwei(1_000_000_000)}},
|
|
||||||
}
|
|
||||||
// SSTORE(5, 0x2a); ADDRESS; SELFDESTRUCT.
|
|
||||||
initcode := []byte{0x60, 0x2a, 0x60, 0x05, 0x55, 0x30, 0xff}
|
|
||||||
db, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(_ int, b *BlockGen) {
|
|
||||||
b.AddTx(types.MustSignNewTx(key, signer, &types.DynamicFeeTx{
|
|
||||||
ChainID: gspec.Config.ChainID,
|
|
||||||
Nonce: 0,
|
|
||||||
Gas: 1_000_000,
|
|
||||||
GasFeeCap: newGwei(5),
|
|
||||||
GasTipCap: newGwei(5),
|
|
||||||
Value: value,
|
|
||||||
Data: initcode,
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
chain, err := NewBlockChain(db, gspec, engine, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to create chain: %v", err)
|
|
||||||
}
|
|
||||||
defer chain.Stop()
|
|
||||||
state, err := chain.StateAt(blocks[0].Header())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to obtain block state: %v", err)
|
|
||||||
}
|
|
||||||
if got := state.GetBalance(created).ToBig(); got.Cmp(value) != 0 {
|
|
||||||
t.Errorf("created balance = %v, want %v", got, value)
|
|
||||||
}
|
|
||||||
if got := state.GetNonce(created); got != 0 {
|
|
||||||
t.Errorf("created nonce = %d, want 0", got)
|
|
||||||
}
|
|
||||||
if got := state.GetCodeSize(created); got != 0 {
|
|
||||||
t.Errorf("created code size = %d, want 0", got)
|
|
||||||
}
|
|
||||||
if got := state.GetState(created, slot); got != (common.Hash{}) {
|
if got := state.GetState(created, slot); got != (common.Hash{}) {
|
||||||
t.Errorf("created storage slot %x = %x, want 0 (stored %x before selfdestruct)", slot, got, stored)
|
t.Errorf("created storage slot %x = %x, want 0 (storage must be cleared)", slot, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue