Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: check witness when contract creation fails #333

Merged
merged 7 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions core/state_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package core

import (
"bytes"
"crypto/ecdsa"

//"fmt"
Expand Down Expand Up @@ -542,3 +543,132 @@ func TestProcessVerkle(t *testing.T) {
}
}
}

func TestProcessVerkleiInvalidContractCreation(t *testing.T) {
var (
config = &params.ChainConfig{
ChainID: big.NewInt(69420),
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
Ethash: new(params.EthashConfig),
ShanghaiTime: u64(0),
PragueTime: u64(0),
TerminalTotalDifficulty: common.Big0,
TerminalTotalDifficultyPassed: true,
ProofInBlocks: true,
}
bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain
gendb = rawdb.NewMemoryDatabase() // Database for the block-generation code, they must be separate as they are path-based.
coinbase = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7")
account1 = common.HexToAddress("0x687704DB07e902e9A8B3754031D168D46E3D586e")
account2 = common.HexToAddress("0x6177843db3138ae69679A54b95cf345ED759450d")
gspec = &Genesis{
Config: config,
Alloc: GenesisAlloc{
coinbase: GenesisAccount{
Balance: big.NewInt(1000000000000000000), // 1 ether
Nonce: 0,
},
account1: GenesisAccount{
Balance: big.NewInt(1000000000000000000), // 1 ether
Nonce: 0,
},
account2: GenesisAccount{
Balance: big.NewInt(1000000000000000000), // 1 ether
Nonce: 1,
},
},
}
)
Comment on lines +574 to +591
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these values are chosen to simulate the state of kaustinen on blocks 13 and 16, since that's what these problematic txs are taken from.

// Verkle trees use the snapshot, which must be enabled before the
// data is saved into the tree+database.
genesis := gspec.MustCommit(bcdb)

// Commit the genesis block to the block-generation database as it
// is now independent of the blockchain database.
gspec.MustCommit(gendb)

// Create two blocks that reproduce what is happening on kaustinen.
// - The first block contains two failing contract creation transactions, that write to storage before they revert.
// - The second block contains a single failing contract creation transaction, that fails right off the bat.
_, _, _, statediff := GenerateVerkleChain(gspec.Config, genesis, beacon.New(ethash.NewFaker()), gendb, 2, func(i int, gen *BlockGen) {
gen.SetPoS()

if i == 0 {
var tx1, tx2, tx3 types.Transaction
// SSTORE at slot 105 and reverts
tx1payload := common.Hex2Bytes("f8d48084479c2c18830186a08080b8806000602955bda3f9600060ca55600060695523b360006039551983576000601255b0620c2fde2c592ac2600060bc55e0ac6000606455a63e22600060e655eb607e605c5360a2605d5360c7605e53601d605f5360eb606053606b606153608e60625360816063536079606453601e60655360fc60665360b7606753608b60685383021e7ca0cc20c65a97d2e526b8ec0f4266e8b01bdcde43b9aeb59d8bfb44e8eb8119c109a07a8e751813ae1b2ce734960dbc39a4f954917d7822a2c5d1dca18b06c584131f")
gballet marked this conversation as resolved.
Show resolved Hide resolved
if err := tx1.UnmarshalBinary(tx1payload); err != nil {
t.Fatal(err)
}
gen.AddTx(&tx1)

// SSTORE at slot 133 and reverts
tx2payload := common.Hex2Bytes("02f8db83010f2c01843b9aca0084479c2c18830186a08080b88060006085553fad6000600a55600060565555600060b55506600060cf557f1b8b38183e7bd1bdfaa7123c5a4976e54cce0e42049d841411978fd3595e25c66019527f0538943712953cf08900aae40222a40b2d5a4ac8075ad8cf0870e2be307edbb96039527f9f3174ff85024747041ae7a611acffb987c513c088d90ab288aec080a0cd6ac65ce2cb0a912371f6b5a551ba8caffc22ec55ad4d3cb53de41d05eb77b6a02e0dfe8513dfa6ec7bfd7eda6f5c0dac21b39b982436045e128cec46cfd3f960")
gballet marked this conversation as resolved.
Show resolved Hide resolved
if err := tx2.UnmarshalBinary(tx2payload); err != nil {
t.Fatal(err)
}
gen.AddTx(&tx2)

// this one is a simple transfer that succeeds, necessary to get the correct nonce in the other block.
tx3payload := common.Hex2Bytes("f8e80184479c2c18830186a094bbbbde4ca27f83fc18aa108170547ff57675936a80b8807ff71f7c15faadb969a76a5f54a81a0117e1e743cb7f24e378eda28442ea4c6eb6604a527fb5409e5718d44e23bfffac926e5ea726067f772772e7e19446acba0c853f62f5606a526020608a536088608b536039608c536004608d5360af608e537f7f7675d9f210e0a61564e6d11e7cd75f5bc9009ac9f6b94a0fc63035441a83021e7ba04a4a172d81ebb02847829b76a387ac09749c8b65668083699abe20c887fb9efca07c5b1a990702ec7b31a5e8e3935cd9a77649f8c25a84131229e24ab61aec6093")
if err := tx3.UnmarshalBinary(tx3payload); err != nil {
t.Fatal(err)
}
gen.AddTx(&tx3)
} else {
var tx types.Transaction
// immediately reverts
txpayload := common.Hex2Bytes("01f8d683010f2c028443ad7d0e830186a08080b880b00e7fa3c849dce891cce5fae8a4c46cbb313d6aec0c0ffe7863e05fb7b22d4807674c6055527ffbfcb0938f3e18f7937aa8fa95d880afebd5c4cec0d85186095832d03c85cf8a60755260ab60955360cf6096536066609753606e60985360fa609953609e609a53608e609b536024609c5360f6609d536072609e5360a4609fc080a08fc6f7101f292ff1fb0de8ac69c2d320fbb23bfe61cf327173786ea5daee6e37a044c42d91838ef06646294bf4f9835588aee66243b16a66a2da37641fae4c045f")
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

immediately reverts.

gballet marked this conversation as resolved.
Show resolved Hide resolved
if err := tx.UnmarshalBinary(txpayload); err != nil {
t.Fatal(err)
}
gen.AddTx(&tx)
}
})

// Check that values 0x29 and 0x05 are found in the storage (and that they lead
// to no update, since the contract creation code reverted)
for _, stemStateDiff := range statediff[0] {
// Check that the value 0x85, which is overflowing the account header,
// is present.
if bytes.Equal(stemStateDiff.Stem[:], common.Hex2Bytes("a10042195481d30478251625e1ccef0e2174dc4e083e81d2566d880373f791")) {
for _, suffixDiff := range stemStateDiff.SuffixDiffs {
if suffixDiff.Suffix != 133 {
t.Fatalf("invalid suffix diff found for %x in block #1: %d\n", stemStateDiff.Stem, suffixDiff.Suffix)
}
}
} else if bytes.Equal(stemStateDiff.Stem[:], common.Hex2Bytes("b24fa84f214459af17d6e3f604811f252cac93146f02d67d7811bbcdfa448b")) {
for _, suffixDiff := range stemStateDiff.SuffixDiffs {
if suffixDiff.Suffix != 105 && suffixDiff.Suffix != 0 && suffixDiff.Suffix != 2 && suffixDiff.Suffix != 3 {
t.Fatalf("invalid suffix diff found for %x in block #1: %d\n", stemStateDiff.Stem, suffixDiff.Suffix)
}
}
} else {
for _, suffixDiff := range stemStateDiff.SuffixDiffs {
if suffixDiff.Suffix > 4 {
t.Fatalf("invalid suffix diff found for %x in block #1: %d\n", stemStateDiff.Stem, suffixDiff.Suffix)
}
}
}
}

// Check that no account has a value above 4 in the 2nd block as no storage nor
// code should make it to the witness.
for _, stemStateDiff := range statediff[1] {
for _, suffixDiff := range stemStateDiff.SuffixDiffs {
if suffixDiff.Suffix > 4 {
t.Fatalf("invalid suffix diff found for %x in block #2: %d\n", stemStateDiff.Stem, suffixDiff.Suffix)
}
}
}
}
35 changes: 12 additions & 23 deletions trie/utils/verkle.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,28 +186,6 @@ func GetTreeKeyCodeChunkWithEvaluatedAddress(addressPoint *verkle.Point, chunk *
return GetTreeKeyWithEvaluatedAddess(addressPoint, treeIndex, subIndex)
}

func GetTreeKeyStorageSlot(address []byte, storageKey *uint256.Int) []byte {
pos := storageKey.Clone()
if storageKey.Cmp(codeStorageDelta) < 0 {
pos.Add(HeaderStorageOffset, storageKey)
} else {
pos.Add(MainStorageOffset, storageKey)
}
treeIndex := new(uint256.Int).Div(pos, VerkleNodeWidth)

// calculate the sub_index, i.e. the index in the stem tree.
// Because the modulus is 256, it's the last byte of treeIndex
subIndexMod := new(uint256.Int).Mod(pos, VerkleNodeWidth)
var subIndex byte
if len(subIndexMod) != 0 {
// uint256 is broken into 4 little-endian quads,
// each with native endianness. Extract the least
// significant byte.
subIndex = byte(subIndexMod[0])
}
return GetTreeKey(address, treeIndex, subIndex)
}

Comment on lines -189 to -210
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is not used anywhere, and is buggy. Removing it.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not buggy, as it turns out, but still unnecessary

func PointToHash(evaluated *verkle.Point, suffix byte) []byte {
// The output of Byte() is big engian for banderwagon. This
// introduces an imbalance in the tree, because hashes are
Expand Down Expand Up @@ -289,12 +267,23 @@ func GetTreeKeyStorageSlotTreeIndexes(storageKey []byte) (*uint256.Int, byte) {
}
// If the storage slot is in the main storage, we need to add the main storage offset.

// The first MAIN_STORAGE_OFFSET group will see its
// first 64 slots unreachable. This is either a typo in the
// spec or intended to conserve the 256-u256
// aligment. If we decide to ever access these 64
// slots, uncomment this.
// // Get the new offset since we now know that we are above 64.
// pos.Sub(&pos, codeStorageDelta)
// suffix := byte(pos[0] & 0xFF)
suffix := storageKey[len(storageKey)-1]

// We first divide by VerkleNodeWidth to create room to avoid an overflow next.
pos.Rsh(&pos, uint(VerkleNodeWidthLog2))

// We add mainStorageOffset/VerkleNodeWidth which can't overflow.
pos.Add(&pos, mainStorageOffsetLshVerkleNodeWidth)

// The sub-index is the LSB of the original storage key, since mainStorageOffset
// doesn't affect this byte, so we can avoid masks or shifts.
return &pos, storageKey[len(storageKey)-1]
return &pos, suffix
}
Loading