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

fix: code chunification with incorrect header #89

Merged
merged 6 commits into from
Mar 16, 2022
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
24 changes: 14 additions & 10 deletions core/state/state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,19 +275,23 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
s.setError(err)
}
value.SetBytes(content)
}

// Capture the initial value of the location in the verkle proof witness
if s.db.GetTrie().IsVerkle() {
if err != nil {
s.setError(err)
return common.Hash{}
}
addr := s.Address()
loc := new(uint256.Int).SetBytes(key[:])
index := trieUtils.GetTreeKeyStorageSlot(addr[:], loc)
s.db.Witness().SetLeafValue(index, content)
// Capture the initial value of the location in the verkle proof witness
if s.db.GetTrie().IsVerkle() {
if err != nil {
return common.Hash{}
}
addr := s.Address()
loc := new(uint256.Int).SetBytes(key[:])
index := trieUtils.GetTreeKeyStorageSlot(addr[:], loc)
if len(enc) > 0 {
s.db.Witness().SetLeafValue(index, value.Bytes())
} else {
s.db.Witness().SetLeafValue(index, nil)
}
}

s.originStorage[key] = value
return value
}
Expand Down
4 changes: 2 additions & 2 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ func (s *StateDB) updateStateObject(obj *stateObject) {
}

if obj.dirtyCode {
if chunks, err := trie.ChunkifyCode(addr, obj.code); err == nil {
if chunks, err := trie.ChunkifyCode(obj.code); err == nil {
for i := range chunks {
s.trie.TryUpdate(trieUtils.GetTreeKeyCodeChunk(addr[:], uint256.NewInt(uint64(i))), chunks[i][:])
}
Expand Down Expand Up @@ -1014,7 +1014,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
// Write any contract code associated with the state object
if obj.code != nil && obj.dirtyCode {
if s.trie.IsVerkle() {
if chunks, err := trie.ChunkifyCode(addr, obj.code); err == nil {
if chunks, err := trie.ChunkifyCode(obj.code); err == nil {
for i := range chunks {
s.trie.TryUpdate(trieUtils.GetTreeKeyCodeChunk(addr[:], uint256.NewInt(uint64(i))), chunks[i][:])
}
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ github.com/crate-crypto/go-ipa v0.0.0-20220114181434-991b62f9b1da h1:2luwsOSyUPV
github.com/crate-crypto/go-ipa v0.0.0-20220114181434-991b62f9b1da/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI=
github.com/crate-crypto/go-ipa v0.0.0-20220120174240-fe21866d2ad5 h1:BsLconJDsODyRO72xjBHhxZKPCuY/kBgZdPeV4GFNlU=
github.com/crate-crypto/go-ipa v0.0.0-20220120174240-fe21866d2ad5/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI=
github.com/crate-crypto/go-ipa v0.0.0-20220309173511-816621cb2ec4 h1:6KIFkDoBRVfE2I4cUt2wUuejBs+ReEe0cNQnTLs8AwE=
github.com/crate-crypto/go-ipa v0.0.0-20220309173511-816621cb2ec4/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
Expand Down Expand Up @@ -175,6 +177,8 @@ github.com/gballet/go-verkle v0.0.0-20220217102726-664ad58b43cd h1:kvZpVdKgiVfxi
github.com/gballet/go-verkle v0.0.0-20220217102726-664ad58b43cd/go.mod h1:NhFaKv4U1IBG8QkKCsKh4xBMmdori0B0eZjdywcrktE=
github.com/gballet/go-verkle v0.0.0-20220228192133-5773319d4d56 h1:Zucd5Snqq+pzzpOuuj675QgOKvfWxpnouTqug4trGIA=
github.com/gballet/go-verkle v0.0.0-20220228192133-5773319d4d56/go.mod h1:mxWdGqfhWGZ0ckAEg+zHM8u4p1Tsw9mAsbSBtXb9AQE=
github.com/gballet/go-verkle v0.0.0-20220309192943-d9f613553c79 h1:IGryvoVakS5ANetCp33JpA/3eW9A9/k6Ucbqr1rA5uU=
github.com/gballet/go-verkle v0.0.0-20220309192943-d9f613553c79/go.mod h1:S2TbrZxLyGqCqwtl2IA09xxun6oretK6byC1lHY+sAk=
github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
Expand Down
55 changes: 46 additions & 9 deletions trie/verkle.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,29 +308,66 @@ func deserializeVerkleProof(serialized []byte) (*verkle.Proof, []*verkle.Point,
// Copy the values here so as to avoid an import cycle
const (
PUSH1 = 0x60
PUSH32 = 0x71
PUSH32 = 0x7f
)

func ChunkifyCode(addr common.Address, code []byte) ([][32]byte, error) {
lastOffset := byte(0)
chunkCount := len(code) / 31
func ChunkifyCode(code []byte) ([][32]byte, error) {
var (
chunkOffset = 0 // offset in the chunk
chunkCount = len(code) / 31
codeOffset = 0 // offset in the code
)
if len(code)%31 != 0 {
chunkCount++
}
chunks := make([][32]byte, chunkCount)
for i := range chunks {

// number of bytes to copy, 31 unless
// the end of the code has been reached.
end := 31 * (i + 1)
if len(code) < end {
end = len(code)
}

// Copy the code itself
copy(chunks[i][1:], code[31*i:end])
for j := lastOffset; int(j) < len(code[31*i:end]); j++ {
if code[j] >= byte(PUSH1) && code[j] <= byte(PUSH32) {
j += code[j] - byte(PUSH1) + 1
lastOffset = (j + 1) % 31

// chunk offset = taken from the
// last chunk.
if chunkOffset > 31 {
// skip offset calculation if push
// data covers the whole chunk
chunks[i][0] = 31
chunkOffset = 1
continue
}
chunks[i][0] = byte(chunkOffset)
chunkOffset = 0

// Check each instruction and update the offset
// it should be 0 unless a PUSHn overflows.
for ; codeOffset < end; codeOffset++ {
if code[codeOffset] >= PUSH1 && code[codeOffset] <= PUSH32 {
codeOffset += int(code[codeOffset]) - PUSH1 + 1
if codeOffset+1 >= 31*(i+1) {
codeOffset++
chunkOffset = codeOffset - 31*(i+1)
break
}
}
}
chunks[i][0] = lastOffset
}

// if PUSHDATA went past the code end, add 0-filled chunks with
// the correct offset.
if chunkOffset > 0 {

if chunkOffset > 31 {
chunks = append(chunks, [32]byte{31}, [32]byte{1})
} else {
chunks = append(chunks, [32]byte{byte(chunkOffset)})
}
}

return chunks, nil
Expand Down
177 changes: 177 additions & 0 deletions trie/verkle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
package trie

import (
"encoding/hex"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/gballet/go-verkle"
)

Expand Down Expand Up @@ -87,3 +89,178 @@ func TestReproduceTree(t *testing.T) {
t.Logf("serialized: %x", p)
t.Logf("tree: %s\n%x\n", verkle.ToDot(root), root.ComputeCommitment().Bytes())
}

func TestChunkifyCodeTestnet(t *testing.T) {
code, _ := hex.DecodeString("6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea264697066735822122000382db0489577c1646ea2147a05f92f13f32336a32f1f82c6fb10b63e19f04064736f6c63430008070033")
chunks, err := ChunkifyCode(code)
if err != nil {
t.Fatal(err)
}
if len(chunks) != (len(code)+30)/31 {
t.Fatalf("invalid length %d", len(chunks))
}
if chunks[0][0] != 0 {
t.Fatalf("invalid offset in first chunk %d != 0", chunks[0][0])
}
t.Logf("%x\n", chunks[0])
for i, chunk := range chunks[1:] {
if chunk[0] != 0 && i != 4 {
t.Fatalf("invalid offset in chunk #%d %d != 0", i+1, chunk[0])
}
if i == 4 && chunk[0] != 12 {
t.Fatalf("invalid offset in chunk #%d %d != 0", i+1, chunk[0])
}
}
t.Logf("code=%x, chunks=%x\n", code, chunks)

code, _ = hex.DecodeString("608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220d8add45a339f741a94b4fe7f22e101b560dc8a5874cbd957a884d8c9239df86264736f6c63430008070033")
chunks, err = ChunkifyCode(code)
if err != nil {
t.Fatal(err)
}
if len(chunks) != (len(code)+30)/31 {
t.Fatalf("invalid length %d", len(chunks))
}
if chunks[0][0] != 0 {
t.Fatalf("invalid offset in first chunk %d != 0", chunks[0][0])
}
t.Logf("%x\n", chunks[0])
expected := []byte{0, 1, 0, 13, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3}
for i, chunk := range chunks[1:] {
if chunk[0] != expected[i] {
t.Fatalf("invalid offset in chunk #%d %d != %d", i+1, chunk[0], expected[i])
}
}
t.Logf("code=%x, chunks=%x\n", code, chunks)

code, _ = hex.DecodeString("6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea2646970667358221220163c79eab5630c3dbe22f7cc7692da08575198dda76698ae8ee2e3bfe62af3de64736f6c63430008070033")
chunks, err = ChunkifyCode(code)
if err != nil {
t.Fatal(err)
}
if len(chunks) != (len(code)+30)/31 {
t.Fatalf("invalid length %d", len(chunks))
}
if chunks[0][0] != 0 {
t.Fatalf("invalid offset in first chunk %d != 0", chunks[0][0])
}
expected = []byte{0, 0, 0, 0, 13}
for i, chunk := range chunks[1:] {
if chunk[0] != expected[i] {
t.Fatalf("invalid offset in chunk #%d %d != %d", i+1, chunk[0], expected[i])
}
}
t.Logf("code=%x, chunks=%x\n", code, chunks)
}

func TestChunkifyCodeSimple(t *testing.T) {
code := []byte{
0, byte(vm.PUSH4), 1, 2, 3, 4, byte(vm.PUSH3), 58, 68, 12, byte(vm.PUSH21), 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
// Second 31 bytes
0, byte(vm.PUSH21), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
byte(vm.PUSH7), 1, 2, 3, 4, 5, 6, 7,
// Third 31 bytes
byte(vm.PUSH30), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30,
}
t.Logf("code=%x", code)
chunks, err := ChunkifyCode(code)
if err != nil {
t.Fatal(err)
}
if len(chunks) != 3 {
t.Fatalf("invalid length %d", len(chunks))
}
if chunks[0][0] != 0 {
t.Fatalf("invalid offset in first chunk %d != 0", chunks[0][0])
}
if chunks[1][0] != 1 {
t.Fatalf("invalid offset in second chunk %d != 1, chunk=%x", chunks[1][0], chunks[1])
}
if chunks[2][0] != 0 {
t.Fatalf("invalid offset in third chunk %d != 0", chunks[2][0])
}
t.Logf("code=%x, chunks=%x\n", code, chunks)
}

func TestChunkifyCodeFuzz(t *testing.T) {
code := []byte{
3, PUSH32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
}
chunks, err := ChunkifyCode(code)
if err != nil {
t.Fatal(err)
}
if len(chunks) != 2 {
t.Fatalf("invalid length %d", len(chunks))
}
if chunks[0][0] != 0 {
t.Fatalf("invalid offset in first chunk %d != 0", chunks[0][0])
}
if chunks[1][0] != 3 {
t.Fatalf("invalid offset in second chunk %d != 3, chunk=%x", chunks[1][0], chunks[1])
}
t.Logf("code=%x, chunks=%x\n", code, chunks)

code = []byte{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, PUSH32,
}
chunks, err = ChunkifyCode(code)
if err != nil {
t.Fatal(err)
}
if len(chunks) != 3 {
t.Fatalf("invalid length %d", len(chunks))
}
if chunks[0][0] != 0 {
t.Fatalf("invalid offset in first chunk %d != 0", chunks[0][0])
}
if chunks[1][0] != 31 {
t.Fatalf("invalid offset in second chunk %d != 31, chunk=%x", chunks[1][0], chunks[1])
}
if chunks[2][0] != 1 {
t.Fatalf("invalid offset in third chunk %d != 1, chunk=%x", chunks[2][0], chunks[1])
}
t.Logf("code=%x, chunks=%x\n", code, chunks)

code = []byte{
byte(vm.PUSH4), PUSH32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}
chunks, err = ChunkifyCode(code)
if err != nil {
t.Fatal(err)
}
if len(chunks) != 2 {
t.Fatalf("invalid length %d", len(chunks))
}
if chunks[0][0] != 0 {
t.Fatalf("invalid offset in first chunk %d != 0", chunks[0][0])
}
if chunks[1][0] != 0 {
t.Fatalf("invalid offset in second chunk %d != 0, chunk=%x", chunks[1][0], chunks[1])
}
t.Logf("code=%x, chunks=%x\n", code, chunks)

code = []byte{
byte(vm.PUSH4), PUSH32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}
chunks, err = ChunkifyCode(code)
if err != nil {
t.Fatal(err)
}
if len(chunks) != 2 {
t.Fatalf("invalid length %d", len(chunks))
}
if chunks[0][0] != 0 {
t.Fatalf("invalid offset in first chunk %d != 0", chunks[0][0])
}
if chunks[1][0] != 0 {
t.Fatalf("invalid offset in second chunk %d != 0, chunk=%x", chunks[1][0], chunks[1])
}
t.Logf("code=%x, chunks=%x\n", code, chunks)
}