Skip to content

Commit

Permalink
Merge pull request #6 from sircoon4/feature-merkel-trie-proof
Browse files Browse the repository at this point in the history
  • Loading branch information
eseiker authored Jul 22, 2024
2 parents 8fd32ab + c546815 commit 46f5a36
Show file tree
Hide file tree
Showing 9 changed files with 381 additions and 2 deletions.
32 changes: 32 additions & 0 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/crypto/bn256"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/crypto/secp256r1"
"github.com/ethereum/go-ethereum/libplanet"
"github.com/ethereum/go-ethereum/params"
"golang.org/x/crypto/ripemd160"
)
Expand Down Expand Up @@ -122,6 +123,7 @@ var PrecompiledContractsFjord = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
common.BytesToAddress([]byte{0x02, 0x00}): &libplanetVerifyProof{},
}

// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
Expand Down Expand Up @@ -1191,3 +1193,33 @@ func (c *p256Verify) Run(input []byte) ([]byte, error) {
return nil, nil
}
}

// LibplanetVerifyProof implemented for verifying merkle trie proof
// from blockchain networks built by Libplanet.
type libplanetVerifyProof struct{}

func (c *libplanetVerifyProof) RequiredGas(input []byte) uint64 {
return params.LibplanetVerifyProofGas
}

func (c *libplanetVerifyProof) Run(input []byte) ([]byte, error) {
proofMap := map[string]any{
"stateRootHash": nil, // sha256(bencoded) []byte
"proof": nil, // bencoded list [][]byte
"key": nil, // keyBytes []byte
"value": nil, // bencoded []byte
}
proofMap, err := libplanet.ParseMerkleTrieProofInput(input)
if err != nil {
return nil, err
}

stateRootHash := proofMap["stateRootHash"].([]byte)
proof := proofMap["proof"].([][]byte)
key := proofMap["key"].([]byte)
value := proofMap["value"].([]byte)

valid, _ := libplanet.ValidateProof(stateRootHash, proof, key, value)

return common.CopyBytes(libplanet.BoolAbi(valid)), nil
}
5 changes: 4 additions & 1 deletion core/vm/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ var allPrecompiles = map[common.Address]PrecompiledContract{

common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},

common.BytesToAddress([]byte{0x02, 0x00}): &libplanetVerifyProof{},

common.BytesToAddress([]byte{0x0f, 0x0a}): &bls12381G1Add{},
common.BytesToAddress([]byte{0x0f, 0x0b}): &bls12381G1Mul{},
common.BytesToAddress([]byte{0x0f, 0x0c}): &bls12381G1MultiExp{},
Expand Down Expand Up @@ -408,4 +410,5 @@ func BenchmarkPrecompiledP256Verify(bench *testing.B) {
benchmarkPrecompiled("100", t, bench)
}

func TestPrecompiledP256Verify(t *testing.T) { testJson("p256Verify", "100", t) }
func TestPrecompiledP256Verify(t *testing.T) { testJson("p256Verify", "100", t) }
func TestPrecompiledLibplanetVerifyProof(t *testing.T) { testJson("libplanetVerifyProof", "200", t) }
50 changes: 50 additions & 0 deletions core/vm/testdata/precompiles/libplanetVerifyProof.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000020979a00921d42d2ca63e98c1c2ac07f0eacbb99e363b8f2f7f8e4d19c854b6c200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000286c313a0033323a84cac50effba60ce08415ff3356839fa032a91658a7740d60ffba4af6245a0c565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c6c33323ab7ba99008cd22b95a8fce03c7d2d72ca2352732ad0a849b91653b12ab07cce4c6c6e75323a3031656e6e6e6e6e6e6e6e6e6e6e6e6e6e6e6500000000000000000000000000000000000000000000000000000000000000000000004a6c6c313a006c6e75343a30303030656533323a3edb1a2151507f2c3853e1b3a8039ec5768b22e71c268f49d12addbb6806b3f16e6e6e6e6e6e6e6e6e6e6e6e6e6e6c6e75323a303065650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000575323a3030000000000000000000000000000000000000000000000000000000",
"Expected": "0000000000000000000000000000000000000000000000000000000000000001",
"Name": "sample00",
"Gas": 3000
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000020979a00921d42d2ca63e98c1c2ac07f0eacbb99e363b8f2f7f8e4d19c854b6c200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000286c313a0033323a84cac50effba60ce08415ff3356839fa032a91658a7740d60ffba4af6245a0c565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c6c33323ab7ba99008cd22b95a8fce03c7d2d72ca2352732ad0a849b91653b12ab07cce4c6c6e75323a3031656e6e6e6e6e6e6e6e6e6e6e6e6e6e6e650000000000000000000000000000000000000000000000000000000000000000000000010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000575323a3031000000000000000000000000000000000000000000000000000000",
"Expected": "0000000000000000000000000000000000000000000000000000000000000001",
"Name": "sample01",
"Gas": 3000
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000020979a00921d42d2ca63e98c1c2ac07f0eacbb99e363b8f2f7f8e4d19c854b6c200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000286c313a0033323a84cac50effba60ce08415ff3356839fa032a91658a7740d60ffba4af6245a0c565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c6c33323ab7ba99008cd22b95a8fce03c7d2d72ca2352732ad0a849b91653b12ab07cce4c6c6e75323a3031656e6e6e6e6e6e6e6e6e6e6e6e6e6e6e6500000000000000000000000000000000000000000000000000000000000000000000004a6c6c313a006c6e75343a30303030656533323a3edb1a2151507f2c3853e1b3a8039ec5768b22e71c268f49d12addbb6806b3f16e6e6e6e6e6e6e6e6e6e6e6e6e6e6c6e75323a303065650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000775343a3030303000000000000000000000000000000000000000000000000000",
"Expected": "0000000000000000000000000000000000000000000000000000000000000001",
"Name": "sample0000",
"Gas": 3000
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000020979a00921d42d2ca63e98c1c2ac07f0eacbb99e363b8f2f7f8e4d19c854b6c20000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000286c313a0033323a84cac50effba60ce08415ff3356839fa032a91658a7740d60ffba4af6245a0c565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c6c33323ab7ba99008cd22b95a8fce03c7d2d72ca2352732ad0a849b91653b12ab07cce4c6c6e75323a3031656e6e6e6e6e6e6e6e6e6e6e6e6e6e6e6500000000000000000000000000000000000000000000000000000000000000000000004a6c6c313a006c6e75343a30303030656533323a3edb1a2151507f2c3853e1b3a8039ec5768b22e71c268f49d12addbb6806b3f16e6e6e6e6e6e6e6e6e6e6e6e6e6e6c6e75323a303065650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000286c313a0033323ab16b9db1bce3fedf7dd114b02938f2476c21936a3f30fffecc8db14d377d3dd96500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000276c6e7533323a303030303030303030303030303030303030303030303030303030303030313065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247533323a303030303030303030303030303030303030303030303030303030303030313000000000000000000000000000000000000000000000000000000000",
"Expected": "0000000000000000000000000000000000000000000000000000000000000001",
"Name": "sample0010",
"Gas": 3000
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000000206cc5c2ca1b7b146268f0d930c58c7e5441b807e72cf16d56f52c869a594b17bf0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000286c313a0033323a84cac50effba60ce08415ff3356839fa032a91658a7740d60ffba4af6245a0c565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c6c33323ab7ba99008cd22b95a8fce03c7d2d72ca2352732ad0a849b91653b12ab07cce4c6c6e75323a3031656e6e6e6e6e6e6e6e6e6e6e6e6e6e6e6500000000000000000000000000000000000000000000000000000000000000000000004a6c6c313a006c6e75343a30303030656533323a3edb1a2151507f2c3853e1b3a8039ec5768b22e71c268f49d12addbb6806b3f16e6e6e6e6e6e6e6e6e6e6e6e6e6e6c6e75323a303065650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000575323a3030000000000000000000000000000000000000000000000000000000",
"Expected": "0000000000000000000000000000000000000000000000000000000000000000",
"Name": "sampleFalseHash",
"Gas": 3000
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000020979a00921d42d2ca63e98c1c2ac07f0eacbb99e363b8f2f7f8e4d19c854b6c200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000286c313a0033323a84cac50effba60ce08415ff3356839fa032a91658a7740d60ffba4af6245a0c565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c6c33323ab7ba99008cd22b95a8fce03c7d2d72ca2352732ad0a849b91653b12ab07cce4c6c6e75323a3031656e6e6e6e6e6e6e6e6e6e6e6e6e6e6e6500000000000000000000000000000000000000000000000000000000000000000000004a6c6c313a006c6e75343a30303030656533323a3edb1a2151507f2c3853e1b3a8039ec5768b22e71c268f49d12addbb6806b3f16e6e6e6e6e6e6e6e6e6e6e6e6e6e6c6e75323a303065650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000575323a3031000000000000000000000000000000000000000000000000000000",
"Expected": "0000000000000000000000000000000000000000000000000000000000000000",
"Name": "sampleFalseValue",
"Gas": 3000
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000020979a00921d42d2ca63e98c1c2ac07f0eacbb99e363b8f2f7f8e4d19c854b6c200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000286c313a0033323a84cac50effba60ce08415ff3356839fa032a91658a7740d60ffba4af6245a0c565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c6c33323ab7ba99008cd22b95a8fce03c7d2d72ca2352732ad0a849b91653b12ab07cce4c6c6e75323a3031656e6e6e6e6e6e6e6e6e6e6e6e6e6e6e6500000000000000000000000000000000000000000000000000000000000000000000004a6c6c313a006c6e75343a30303030656533323a3edb1a2151507f2c3853e1b3a8039ec5768b22e71c268f49d12addbb6806b3f16e6e6e6e6e6e6e6e6e6e6e6e6e6e6c6e75323a303065650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000575323a3030000000000000000000000000000000000000000000000000000000",
"Expected": "0000000000000000000000000000000000000000000000000000000000000000",
"Name": "sampleFalseKey",
"Gas": 3000
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000020979a00921d42d2ca63e98c1c2ac07f0eacbb99e363b8f2f7f8e4d19c854b6c200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000286c313a0033323a84cac50effba60ce08415ff3356839fa032a91658a7740d60ffba4af6245a0c565000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c6c33323ab7ba99008cd22b95a8fce03c7d2d72ca2352732ad0a849b91653b12ab07cce4c6c6e75323a3031656e6e6e6e6e6e6e6e6e6e6e6e6e6e6e6500000000000000000000000000000000000000000000000000000000000000000000004a6c6c313a006c6e75343a30303030656533323a3edb1a2151507f2c3853e1b3a8039ec5768b22e71c268f49d12addbb6806b3f16e6e6e6e6e6e6e6e6e6e6e6e6e6e6c6e75323a303065650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000575323a3031000000000000000000000000000000000000000000000000000000",
"Expected": "0000000000000000000000000000000000000000000000000000000000000000",
"Name": "sampleFalseProof",
"Gas": 3000
}
]
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ require (
github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7
github.com/rs/cors v1.7.0
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
github.com/sircoon4/bencodex-go v0.1.6
github.com/status-im/keycard-go v0.2.0
github.com/stretchr/testify v1.8.4
github.com/supranational/blst v0.3.11
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,8 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sircoon4/bencodex-go v0.1.6 h1:VdurGt5ZlDcN5WA9e4jfkLdy5XyzJCoE/vwlq0YJeyY=
github.com/sircoon4/bencodex-go v0.1.6/go.mod h1:w0nk0aVNbOpfNQpo4ogLdyCasC3lmYKg4m+ujyNfNg0=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
Expand Down
105 changes: 105 additions & 0 deletions libplanet/merkle_trie_node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package libplanet

import (
"fmt"

"github.com/sircoon4/bencodex-go"
)

type node interface {
name() string
}

type (
fullNode struct {
Children [17]node
}
shortNode struct {
Key []byte
Value node
}
hashNode []byte // sha256(bencoded)
valueNode []byte // bencoded
)

func (n *fullNode) name() string {
return "fullNode"
}
func (n *shortNode) name() string {
return "shortNode"
}
func (n hashNode) name() string {
return "hashNode"
}
func (n valueNode) name() string {
return "valueNode"
}

func (n *fullNode) GetValue() node {
return n.Children[16]
}
func (n *shortNode) GetValue() node {
return n.Value
}
func (n hashNode) GetValue() []byte {
return n
}
func (n valueNode) GetValue() []byte {
return n
}

func nodeFromProof(proof []byte) (node, error) {
data, err := bencodex.Decode(proof)
if err != nil {
return nil, err
}

return nodeFromData(data)
}

func nodeFromData(data any) (node, error) {
if data == nil {
return nil, nil
}

switch data := data.(type) {
case []byte:
return hashNode(data), nil
case []interface{}:
list := data
if len(list) == 2 {
if list[0] == nil {
value, err := bencodex.Encode(list[1])
if err != nil {
return nil, err
}
return valueNode(value), nil
} else {
value, err := nodeFromData(list[1])
if err != nil {
return nil, err
}
return &shortNode{
Key: list[0].([]byte),
Value: value,
}, nil
}
} else if len(list) == 17 {
children := [17]node{}
for i, child := range list {
var err error
children[i], err = nodeFromData(child)
if err != nil {
return nil, err
}
}
return &fullNode{
Children: children,
}, nil
}
default:
return nil, fmt.Errorf("invalid node")
}

return nil, fmt.Errorf("invalid node")
}
Loading

0 comments on commit 46f5a36

Please sign in to comment.