Skip to content

Commit

Permalink
squash and sign
Browse files Browse the repository at this point in the history
  • Loading branch information
rpl-ffl committed Sep 23, 2024
1 parent 8838baa commit 74fb259
Show file tree
Hide file tree
Showing 16 changed files with 1,765 additions and 25 deletions.
1 change: 1 addition & 0 deletions db/code_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func (db *codeDB) GetCode(codeHash types.Hash) ([]byte, error) {
if err != nil {
return nil, fmt.Errorf("cannot get code %s: %w", codeHash, err)
}

return code, nil
}

Expand Down
37 changes: 28 additions & 9 deletions db/substate_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import (
"encoding/binary"
"fmt"

pb "github.com/Fantom-foundation/Substate/protobuf"
"github.com/Fantom-foundation/Substate/rlp"
"github.com/Fantom-foundation/Substate/substate"
trlp "github.com/Fantom-foundation/Substate/types/rlp"
"github.com/golang/protobuf/proto"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/opt"
"github.com/syndtr/goleveldb/leveldb/util"
Expand Down Expand Up @@ -108,12 +110,19 @@ func (db *substateDB) GetSubstate(block uint64, tx int) (*substate.Substate, err
return nil, fmt.Errorf("cannot get substate block: %v, tx: %v from db; %w", block, tx, err)
}

rlpSubstate, err := rlp.Decode(val)
if err != nil {
return nil, fmt.Errorf("cannot decode data into rlp block: %v, tx %v; %w", block, tx, err)
//rlpSubstate, err := rlp.Decode(val)
//if err != nil {
// return nil, fmt.Errorf("cannot decode data into rlp block: %v, tx %v; %w", block, tx, err)
//}

//return rlpSubstate.ToSubstate(db.GetCode, block, tx)

pbSubstate := &pb.Substate{}
if err := proto.Unmarshal(val, pbSubstate); err != nil {
return nil, err
}

return rlpSubstate.ToSubstate(db.GetCode, block, tx)
return pbSubstate.Decode(db.GetCode, block, tx)
}

// GetBlockSubstates returns substates for given block if exists within DB.
Expand All @@ -138,14 +147,24 @@ func (db *substateDB) GetBlockSubstates(block uint64) (map[int]*substate.Substat
return nil, fmt.Errorf("record-replay: GetBlockSubstates(%v) iterated substates from block %v", block, b)
}

rlpSubstate, err := rlp.Decode(value)
if err != nil {
return nil, fmt.Errorf("cannot decode data into rlp block: %v, tx %v; %w", block, tx, err)
//rlpSubstate, err := rlp.Decode(value)
//if err != nil {
// return nil, fmt.Errorf("cannot decode data into rlp block: %v, tx %v; %w", block, tx, err)
//}

//sbstt, err := rlpSubstate.ToSubstate(db.GetCode, block, tx)
//if err != nil {
// return nil, fmt.Errorf("cannot decode data into substate: %w", err)
//}

pbSubstate := &pb.Substate{}
if err := proto.Unmarshal(value, pbSubstate); err != nil {
return nil, err
}

sbstt, err := rlpSubstate.ToSubstate(db.GetCode, block, tx)
sbstt, err := pbSubstate.Decode(db.GetCode, block, tx)
if err != nil {
return nil, fmt.Errorf("cannot decode data into substate: %w", err)
return nil, err
}

txSubstate[tx] = sbstt
Expand Down
12 changes: 8 additions & 4 deletions db/substate_iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package db
import (
"fmt"

"github.com/golang/protobuf/proto"
"github.com/syndtr/goleveldb/leveldb/util"

"github.com/Fantom-foundation/Substate/rlp"
pb "github.com/Fantom-foundation/Substate/protobuf"
"github.com/Fantom-foundation/Substate/substate"
)

Expand Down Expand Up @@ -33,12 +34,15 @@ func (i *substateIterator) decode(data rawEntry) (*substate.Substate, error) {
return nil, fmt.Errorf("invalid substate key: %v; %w", key, err)
}

rlpSubstate, err := rlp.Decode(value)
if err != nil {
//rlpSubstate, err := rlp.Decode(value)
//return rlpSubstate.ToSubstate(i.db.GetCode, block, tx)

pbSubstate := &pb.Substate{}
if err := proto.Unmarshal(value, pbSubstate); err != nil {
return nil, err
}

return rlpSubstate.ToSubstate(i.db.GetCode, block, tx)
return pbSubstate.Decode(i.db.GetCode, block, tx)
}

func (i *substateIterator) start(numWorkers int) {
Expand Down
283 changes: 283 additions & 0 deletions protobuf/decode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
package protobuf

import (
"errors"
"fmt"
"math/big"

"github.com/Fantom-foundation/Substate/substate"
"github.com/Fantom-foundation/Substate/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/holiman/uint256"
"github.com/syndtr/goleveldb/leveldb"
)

type dbGetCode = func(types.Hash) ([]byte, error)

// Decode converts protobuf-encoded Substate into aida-comprehensible substate
func (s *Substate) Decode(lookup dbGetCode, block uint64, tx int) (*substate.Substate, error) {
input, err := s.GetInputAlloc().decode(lookup)
if err != nil {
return nil, err
}

output, err := s.GetOutputAlloc().decode(lookup)
if err != nil {
return nil, err
}

environment, err := s.GetBlockEnv().decode()
if err != nil {
return nil, err
}

message, err := s.GetTxMessage().decode(lookup)
if err != nil {
return nil, err
}

contractAddress := s.GetTxMessage().getContractAddress()
result, err := s.GetResult().decode(contractAddress)
if err != nil {
return nil, err
}

return &substate.Substate{
InputSubstate: *input,
OutputSubstate: *output,
Env: environment,
Message: message,
Result: result,
Block: block,
Transaction: tx,
}, nil
}

// decode converts protobuf-encoded Substate_Alloc into aida-comprehensible WorldState
func (alloc *Substate_Alloc) decode(lookup dbGetCode) (*substate.WorldState, error) {
world := make(substate.WorldState, len(alloc.GetAlloc()))

for _, entry := range alloc.GetAlloc() {
addr, acct, err := entry.decode()
if err != nil {
return nil, fmt.Errorf("Error decoding alloc entry; %w", err)
}

address := types.BytesToAddress(addr)
nonce, balance, _, codehash, err := acct.decode()
if err != nil {
return nil, fmt.Errorf("Error decoding entry account; %w", err)
}

code, err := lookup(codehash)
if err != nil && !errors.Is(err, leveldb.ErrNotFound) {
return nil, fmt.Errorf("Error looking up codehash; %w", err)
}

world[address] = substate.NewAccount(nonce, balance, code)
for _, storage := range acct.GetStorage() {
key, value, err := storage.decode()
if err != nil {
return nil, fmt.Errorf("Error decoding account storage entry; %w", err)
}
world[address].Storage[key] = value
}
}

return &world, nil
}

func (entry *Substate_AllocEntry) decode() ([]byte, *Substate_Account, error) {
return entry.GetAddress(), entry.GetAccount(), nil
}

func (acct *Substate_Account) decode() (uint64, *uint256.Int, []byte, types.Hash, error) {
return acct.GetNonce(),
types.BytesToUint256(acct.GetBalance()),
acct.GetCode(),
types.BytesToHash(acct.GetCodeHash()),
nil
}

func (entry *Substate_Account_StorageEntry) decode() (types.Hash, types.Hash, error) {
return types.BytesToHash(entry.GetKey()),
types.BytesToHash(entry.GetValue()),
nil
}

// decode converts protobuf-encoded Substate_BlockEnv into aida-comprehensible Env
func (env *Substate_BlockEnv) decode() (*substate.Env, error) {
var blockHashes map[uint64]types.Hash = nil
if env.GetBlockHashes() != nil {
blockHashes = make(map[uint64]types.Hash, len(env.GetBlockHashes()))
for _, entry := range env.GetBlockHashes() {
key, value, err := entry.decode()
if err != nil {
return nil, err
}
blockHashes[key] = types.BytesToHash(value)
}
}

return &substate.Env{
Coinbase: types.BytesToAddress(env.GetCoinbase()),
Difficulty: types.BytesToBigInt(env.GetDifficulty()),
GasLimit: env.GetGasLimit(),
Number: env.GetNumber(),
Timestamp: env.GetTimestamp(),
BlockHashes: blockHashes,
BaseFee: BytesValueToBigInt(env.GetBaseFee()),
Random: BytesValueToHash(env.GetRandom()),
BlobBaseFee: BytesValueToBigInt(env.GetBlobBaseFee()),
}, nil
}

func (entry *Substate_BlockEnv_BlockHashEntry) decode() (uint64, []byte, error) {
return entry.GetKey(), entry.GetValue(), nil
}

// decode converts protobuf-encoded Substate_TxMessage into aida-comprehensible Message
func (msg *Substate_TxMessage) decode(lookup dbGetCode) (*substate.Message, error) {

// to=nil means contract creation
var pTo *types.Address = nil
to := msg.GetTo()
if to != nil {
address := types.BytesToAddress(to.GetValue())
pTo = &address
}

// if InitCodeHash exists:
// 1. code = lookup the code using InitCodeHash
// 2. set data -> code from (1)
// 3. clear InitCodeHash
var data []byte = msg.GetData()
if pTo == nil {
code, err := lookup(types.BytesToHash(msg.GetInitCodeHash()))
if err != nil && !errors.Is(err, leveldb.ErrNotFound) {
return nil, fmt.Errorf("failed to decode tx message; %w", err)
}
data = code
}

txType := msg.GetTxType()

// Berlin hard fork, EIP-2930: Optional access lists
var accessList types.AccessList = nil // nil if EIP-2930 is not activated
switch txType {
case Substate_TxMessage_TXTYPE_ACCESSLIST,
Substate_TxMessage_TXTYPE_DYNAMICFEE,
Substate_TxMessage_TXTYPE_BLOB:

accessList = make([]types.AccessTuple, len(msg.GetAccessList()))
for i, entry := range msg.GetAccessList() {
addr, keys, err := entry.decode()
if err != nil {
return nil, err
}

address := types.BytesToAddress(addr)
storageKeys := make([]types.Hash, len(keys))
for j, key := range keys {
storageKeys[j] = types.BytesToHash(key)
}

accessList[i] = types.AccessTuple{
Address: address,
StorageKeys: storageKeys,
}
}
}

// London hard fork, EIP-1559: Fee market
var gasFeeCap *big.Int = types.BytesToBigInt(msg.GetGasPrice())
var gasTipCap *big.Int = types.BytesToBigInt(msg.GetGasPrice())
switch txType {
case Substate_TxMessage_TXTYPE_DYNAMICFEE,
Substate_TxMessage_TXTYPE_BLOB:

gasFeeCap = BytesValueToBigInt(msg.GetGasFeeCap())
gasTipCap = BytesValueToBigInt(msg.GetGasTipCap())
}

// Cancun hard fork, EIP-4844
var blobHashes []types.Hash = nil
switch txType {
case Substate_TxMessage_TXTYPE_BLOB:
if msg.GetBlobHashes() != nil {
blobHashes = make([]types.Hash, len(msg.GetBlobHashes()))
for i, hash := range msg.GetBlobHashes() {
blobHashes[i] = types.BytesToHash(hash)
}
}
}

return &substate.Message{
Nonce: msg.GetNonce(),
CheckNonce: true,
GasPrice: types.BytesToBigInt(msg.GetGasPrice()),
Gas: msg.GetGas(),
From: types.BytesToAddress(msg.GetFrom()),
To: pTo,
Value: types.BytesToBigInt(msg.GetValue()),
Data: data,
AccessList: accessList,
GasFeeCap: gasFeeCap,
GasTipCap: gasTipCap,
BlobGasFeeCap: BytesValueToBigInt(msg.GetBlobGasFeeCap()),
BlobHashes: blobHashes,
}, nil
}

func (entry *Substate_TxMessage_AccessListEntry) decode() ([]byte, [][]byte, error) {
return entry.GetAddress(), entry.GetStorageKeys(), nil
}

// getContractAddress returns the address of the newly created contract if any.
// returns nil otherwise.
func (msg *Substate_TxMessage) getContractAddress() common.Address {
var contractAddress common.Address

// *to==nil means contract creation and thus address of newly created contract
to := msg.GetTo()
if to == nil {
fromAddr := common.BytesToAddress(msg.GetFrom())
contractAddress = crypto.CreateAddress(fromAddr, msg.GetNonce())
}

return contractAddress
}

// decode converts protobuf-encoded Substate_Result into aida-comprehensible Result
func (res *Substate_Result) decode(contractAddress common.Address) (*substate.Result, error) {
var err error = nil
logs := make([]*types.Log, len(res.GetLogs()))
for i, log := range res.GetLogs() {
logs[i], err = log.decode()
if err != nil {
return nil, fmt.Errorf("Error decoding result; %w", err)
}
}

return substate.NewResult(
res.GetStatus(), // Status
types.BytesToBloom(res.Bloom), // Bloom
logs, // Logs
types.BytesToAddress(contractAddress.Bytes()), // ContractAddress
res.GetGasUsed(), // GasUsed
), nil
}

func (log *Substate_Result_Log) decode() (*types.Log, error) {
topics := make([]types.Hash, len(log.GetTopics()))
for i, topic := range log.GetTopics() {
topics[i] = types.BytesToHash(topic)
}

return &types.Log{
Address: types.BytesToAddress(log.GetAddress()),
Topics: topics,
Data: log.GetData(),
}, nil
}
5 changes: 5 additions & 0 deletions protobuf/protoc-substate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

#go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28.1

protoc --go_out=. substate.proto
Loading

0 comments on commit 74fb259

Please sign in to comment.