Skip to content

Commit

Permalink
feat: implement merkle proofs for account and storage
Browse files Browse the repository at this point in the history
  • Loading branch information
kstdl committed Oct 30, 2023
1 parent 845375e commit 333915d
Show file tree
Hide file tree
Showing 15 changed files with 833 additions and 129 deletions.
6 changes: 6 additions & 0 deletions crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package crypto

import (
"errors"
"hash"
"math/big"

"github.com/Taraxa-project/taraxa-evm/common"
Expand All @@ -34,6 +35,11 @@ var (

var errInvalidPubkey = errors.New("invalid secp256k1 public key")

type KeccakState interface {
hash.Hash
Read([]byte) (int, error)
}

// Keccak256 calculates and returns the Keccak256 hash of the input data.
func Keccak256(data ...[]byte) []byte {
d := sha3.NewLegacyKeccak256()
Expand Down
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
module github.com/Taraxa-project/taraxa-evm

go 1.18
go 1.21

require (
github.com/btcsuite/btcd v0.20.1-beta
github.com/davecgh/go-spew v1.1.1
github.com/emicklei/dot v1.2.0
github.com/holiman/uint256 v1.2.1
github.com/ethereum/go-ethereum v1.13.0
github.com/holiman/uint256 v1.2.3
github.com/linxGnu/grocksdb v1.6.48
github.com/otiai10/copy v1.9.0
github.com/schollz/progressbar/v3 v3.3.3
github.com/stretchr/testify v1.8.1
golang.org/x/crypto v0.3.0
golang.org/x/crypto v0.12.0
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
golang.org/x/sys v0.13.0
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f
)

require (
github.com/kr/text v0.1.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
Expand Down
14 changes: 9 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,28 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emicklei/dot v1.2.0 h1:WjL422LPltH/ThM9AJQ8HJXEMw9SOxLrglppg/1pFYU=
github.com/emicklei/dot v1.2.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
github.com/ethereum/go-ethereum v1.13.0 h1:dZALM0PlDTtNITTECPiqSrFo0iEYVDfby+mSVc0LxIs=
github.com/ethereum/go-ethereum v1.13.0/go.mod h1:0TDsBNJ7j8jR01vKpk4j2zfVKyAbQuKzy6wLwb5ZMuU=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o=
github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o=
github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
Expand Down Expand Up @@ -59,8 +63,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down
2 changes: 1 addition & 1 deletion rlp/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
"github.com/Taraxa-project/taraxa-evm/taraxa/util/bin"
)

const EmptyString = 0x80
const EmptyString = byte(0x80)

var encoderInterface = reflect.TypeOf(new(RLPEncodable)).Elem()

Expand Down
289 changes: 289 additions & 0 deletions taraxa/state/contracts/tests/dpos/trie_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
package dpos_tests

import (
"encoding/json"
"fmt"
"math/big"
"strings"
"testing"

"github.com/holiman/uint256"

"github.com/Taraxa-project/taraxa-evm/accounts/abi"
"github.com/Taraxa-project/taraxa-evm/crypto"
"github.com/Taraxa-project/taraxa-evm/taraxa/state"
dpos "github.com/Taraxa-project/taraxa-evm/taraxa/state/contracts/dpos/precompiled"
"github.com/Taraxa-project/taraxa-evm/taraxa/state/rewards_stats"
"github.com/Taraxa-project/taraxa-evm/taraxa/state/state_db"

"github.com/Taraxa-project/taraxa-evm/taraxa/state/state_db_rocksdb"

"github.com/Taraxa-project/taraxa-evm/taraxa/util/tests"

"github.com/Taraxa-project/taraxa-evm/common"

"github.com/Taraxa-project/taraxa-evm/core/types"
"github.com/Taraxa-project/taraxa-evm/core/vm"
"github.com/Taraxa-project/taraxa-evm/taraxa/state/chain_config"
)

type ContractTest struct {
ChainCfg chain_config.ChainConfig
st state.StateTransition
statedb *state_db_rocksdb.DB
tc *tests.TestCtx
SUT *state.API
blk_n types.BlockNum
abi abi.ABI
ContractAddr *common.Address
Sender common.Address
}

var (
BigZero = big.NewInt(0)
)

func init_contract_test(t *testing.T, cfg chain_config.ChainConfig) (tc tests.TestCtx, test ContractTest) {
tc = tests.NewTestCtx(t)
test.init(&tc, cfg)
return
}

func (self *ContractTest) init(t *tests.TestCtx, cfg chain_config.ChainConfig) {
self.tc = t
self.ChainCfg = cfg

self.Sender = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7")
self.ChainCfg.GenesisBalances[self.Sender] = big.NewInt(int64(9000000000000000000))

self.statedb = new(state_db_rocksdb.DB).Init(state_db_rocksdb.Opts{
Path: self.tc.DataDir(),
})
self.SUT = new(state.API).Init(
self.statedb,
func(num types.BlockNum) *big.Int { panic("unexpected") },
&self.ChainCfg,
state.APIOpts{},
)

self.st = self.SUT.GetStateTransition()
simpleStorageCode := common.Hex2Bytes("608060405234801561001057600080fd5b506000606490505b60fa811015610069578060008190555060648161003591906100a8565b6001819055506001546002600080548152602001908152602001600020819055508080610061906100dc565b915050610018565b50610124565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006100b38261006f565b91506100be8361006f565b92508282019050808211156100d6576100d5610079565b5b92915050565b60006100e78261006f565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361011957610118610079565b5b600182019050919050565b61031c806101336000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80631ab06ee51461005157806329e99f071461006d5780636d4ce63c1461009d578063fbf611a7146100bc575b600080fd5b61006b600480360381019061006691906101ad565b6100ec565b005b610087600480360381019061008291906101ed565b610116565b6040516100949190610229565b60405180910390f35b6100a561012e565b6040516100b3929190610244565b60405180910390f35b6100d660048036038101906100d191906101ed565b61013f565b6040516100e39190610286565b60405180910390f35b81600081905550806001819055508060026000848152602001908152602001600020819055505050565b60026020528060005260406000206000915090505481565b600080600054600154915091509091565b60008160026040516020016101559291906102bd565b604051602081830303815290604052805190602001209050919050565b600080fd5b6000819050919050565b61018a81610177565b811461019557600080fd5b50565b6000813590506101a781610181565b92915050565b600080604083850312156101c4576101c3610172565b5b60006101d285828601610198565b92505060206101e385828601610198565b9150509250929050565b60006020828403121561020357610202610172565b5b600061021184828501610198565b91505092915050565b61022381610177565b82525050565b600060208201905061023e600083018461021a565b92915050565b6000604082019050610259600083018561021a565b610266602083018461021a565b9392505050565b6000819050919050565b6102808161026d565b82525050565b600060208201905061029b6000830184610277565b92915050565b600060ff82169050919050565b6102b7816102a1565b82525050565b60006040820190506102d2600083018561021a565b6102df60208301846102ae565b939250505056fea2646970667358221220eeba4e29abce0ca57ba16aaf3ed2ed6bc73abc754e7e29c81023410857d67e6364736f6c63430008120033")
simpleStorageAbi := `[
{
"inputs": [
{
"internalType": "uint256",
"name": "x",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "y",
"type": "uint256"
}
],
"name": "set",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "get",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "key",
"type": "uint256"
}
],
"name": "getStorageLocationForKey",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "test",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]`
exres := self.Execute(self.Sender, big.NewInt(0), simpleStorageCode)
ej, _ := json.Marshal(exres)
fmt.Println(string(ej))
self.ContractAddr = &exres.NewContractAddr

self.abi, _ = abi.JSON(strings.NewReader(simpleStorageAbi))
}

func (self *ContractTest) Execute(from common.Address, value *big.Int, input []byte) vm.ExecutionResult {
senderNonce := self.GetNonce(from)
senderNonce.Add(senderNonce, big.NewInt(1))

self.blk_n++
self.st.BeginBlock(&vm.BlockInfo{})

res := self.st.ExecuteTransaction(&vm.Transaction{
Value: value,
To: self.ContractAddr,
From: from,
Input: input,
Gas: 10000000,
GasPrice: big.NewInt(1),
Nonce: senderNonce,
})

self.st.EndBlock()
self.st.Commit()
return res
}

func (self *ContractTest) AdvanceBlock(author *common.Address, rewardsStats *rewards_stats.RewardsStats) (root common.Hash, ret *uint256.Int) {
self.blk_n++
if author == nil {
self.st.BeginBlock(&vm.BlockInfo{})
} else {
self.st.BeginBlock(&vm.BlockInfo{Author: *author, GasLimit: 0, Time: 0, Difficulty: nil})
}
ret = self.st.DistributeRewards(rewardsStats)
self.st.EndBlock()
root = self.st.Commit()
return
}

func (self *ContractTest) GetBalance(account common.Address) *big.Int {
var bal_actual *big.Int
self.SUT.ReadBlock(self.blk_n).GetAccount(&account, func(account state_db.Account) {
bal_actual = account.Balance
})
return bal_actual
}

func (self *ContractTest) GetNonce(account common.Address) *big.Int {
nonce := big.NewInt(0)
self.SUT.ReadBlock(self.blk_n).GetAccount(&account, func(account state_db.Account) {
nonce = account.Nonce
})
return nonce
}

func (self *ContractTest) GetDPOSReader() dpos.Reader {
return self.SUT.DPOSReader(self.blk_n)
}

func (self *ContractTest) end() {
self.statedb.Close()
self.tc.Close()
}

func (self *ContractTest) pack(name string, args ...interface{}) []byte {
packed, err := self.abi.Pack(name, args...)
if err != nil {
self.tc.Error(err)
self.tc.FailNow()
}
return packed
}

func (self *ContractTest) unpack(v interface{}, name string, output []byte) error {
err := self.abi.Unpack(v, name, output)
if err != nil {
self.tc.Error(err)
self.tc.FailNow()
}
return err
}

func TestTrieVal(t *testing.T) {
_, test := init_contract_test(t, CopyDefaultChainConfig())
defer test.end()

root, _ := test.AdvanceBlock(nil, nil)
fmt.Println("state root", root.Hex())
fmt.Println("test contract addr", test.ContractAddr.Hex())

// for i := 100; i < 230; i++ {
// code := test.pack("set", big.NewInt(int64(i)), big.NewInt(int64(i+100)))
// // fmt.Println(common.Bytes2Hex(code))
// test.Execute(test.Sender, BigZero, code)
// }
// test.AdvanceBlock(nil, nil, nil)

state := state_db.ExtendedReader{Reader: test.statedb.GetBlockState(test.blk_n)}

// state.GetAccountStorage(test.ContractAddr, &h, func(bytes []byte) {
// fmt.Println("storage", common.Bytes2Hex(bytes))
// })

// state.ForEachStorage(test.ContractAddr, func(h *common.Hash, bytes []byte) {
// // fmt.Println("storage", h.String(), common.Bytes2Hex(bytes))
// fmt.Println("storage", h.String(), common.Bytes2Hex(bytes))
// })

fmt.Println()
fmt.Println()
storage_proof := state.ProveAccountStorage(&root, test.ContractAddr)

for i, r := range storage_proof {
fmt.Println("proof", i, common.Bytes2Hex(r))
}
fmt.Println("stateRoot", root.Hex(), "from proof", common.Bytes2Hex(crypto.Keccak256(storage_proof[0])))
//

fmt.Println()
fmt.Println()
h := common.HexToHash("0x7673bcbb3401a7cbae68f81d40eea2cf35afdaf7ecd016ebf3f02857fcc1260a")
res := state.Prove(test.ContractAddr, &h)
for i, r := range res {
fmt.Println("proof", i, common.Bytes2Hex(r))
}

// var acc state_db.Account
// state.GetAccount(test.ContractAddr, func(a state_db.Account) {
// acc = a
// })
// fmt.Println("account root", acc.StorageRootHash.Hex(), "from proof", common.Bytes2Hex(crypto.Keccak256(res[0])))
// account := state_db.DecodeAccountFromTrie(common.Hex2Bytes("f8470180a0e6af15d077c6a71cd3ee33c674b003f5eccdbc8e9fda867020a37cf3a62bc970a03bb6c927aa8d73f4be3c479e49a5357adc0ff448b5bfea109aaa067d29d6403b82031c"))
// aj, _ := json.Marshal(account)
// fmt.Println(string(aj))

// nextHash af60076e9315d9b41a8c42adeb78fef8551f24acb234f37d9d7537ef9ad2e78f
// rlp node f8f18080a0be6aba9ac1c6352f17e80656c7f0b3953ec8ce0e1f2cfb05ef769bfc37d1d77580a0b7b49995dce6c474becec567a6c96c93da7e0990598ac4dc1affbcd3ad452453a010c7db9de7b9d84c39923dbd3949bce63056bfc5e6f0e8b9c4cab3463b6b878180a09e9e038f1f2f81d0bb0e1f416f50de622e9fcecadb4197c5c2bdce5088c7aa2380a05e1ea58069877ad278bf8365b9e3f5448a10f437314d1d2068d84d927b58c747a0ef4ffe20ccabaf1f61203f68e1d6e00cd25a4f54a782609104630224c2eafc7680a0fb21b3c21a8b1068229c1e1380f327c83bffd17a6036c867839c6eb6552248b880808080
// hash 731f155159fc21ab77a156b7735406bd2510206021b4f3137637cd0c32a80721
}
Loading

0 comments on commit 333915d

Please sign in to comment.