Go语言实现Ethereum上StorageTrie的VerifyProof

先实现一个rlp-decoder

package rlp
import(
	"fmt"
	"errors"
	"encoding/hex"
)
const(
	NIL = iota
	BYTES
	GLIST
)

type Atom interface{}
type Glist struct {
	dat Atom
	typeId int
}
func makeGlistContentGlist() *Glist {
	return &Glist{dat: make([]Atom, 0, 65535), typeId: 2}
}
func makeGlistContentBytes(data []byte) *Glist {
	return &Glist{dat: data, typeId: 1}
}
func (g *Glist) Type() int{
	return g.typeId
}
func _Unserialize(dtr []byte) []Atom {
	atomList := make([]Atom, 0, 65535)
	if len(dtr) == 0 {
		return atomList
	}
	if(dtr[0] < 128){
		return append(append(atomList, makeGlistContentBytes(dtr[0 : 1])), _Unserialize(dtr[1 : ])...)
	}else if dtr[0] < 184 {
		return append(append(atomList, makeGlistContentBytes(dtr[1 : dtr[0] - 127])), _Unserialize(dtr[dtr[0] - 127 : ])...)
	}else if dtr[0] < 192 {
		// dlen = truelen + 1
		dlen := int(dtr[0]) - 182
		tlen := decodelength(dtr[1 : dlen])
		return append(append(atomList, makeGlistContentBytes(dtr[dlen : dlen + tlen])), _Unserialize(dtr[dlen + tlen : ])...)
		//return &Glist{dat:, typeId: 1}
	}else if dtr[0] < 248 {
		// dlen = truelen + 1
		return append(append(atomList, Unserialize(dtr[0 : dtr[0] - 191])), _Unserialize(dtr[dtr[0] - 191 : ])...)
	}else {
		// dlen = truelen + 1
		dlen := int(dtr[0]) - 246
		tlen := decodelength(dtr[1 : dlen])
		// fmt.Println("here",dlen,decodelength(dtr[1 : dlen]))
		return append(append(atomList, Unserialize(dtr[0 : dlen + tlen])), _Unserialize(dtr[dlen + tlen : ])...)
	}
	return atomList
}
func Unserialize(dtr []byte) *Glist {
	if len(dtr) == 0 {
		return makeGlistContentGlist()
	}
	if(dtr[0] < 128){
		if len(dtr) > 1 {
			err := errors.New("superflours")
			fmt.Println(err)
			return nil
		}
		return makeGlistContentBytes(dtr[0 : ])
	}else if dtr[0] < 184 {
		if len(dtr) > int(dtr[0] - 127) {
			err := errors.New("superflours")
			fmt.Println(err)
			return nil
		}
		return makeGlistContentBytes(dtr[1 : ])
	}else if dtr[0] < 192 {
		// dlen = truelen + 1
		//must be uint32, but int for convenience
		dlen := int(dtr[0]) - 182
		tlen := decodelength(dtr[1 : dlen])
		if len(dtr) > tlen + dlen {
			err := errors.New("superflours")
			fmt.Println(err)
			return nil
		}
		//fmt.Println(decodelength(dtr[1 : dlen]))
		return makeGlistContentBytes(dtr[dlen : ])
		//return &Glist{dat:, typeId: 1}
	}else if dtr[0] < 248 {
		// dlen = truelen + 1
		// fmt.Println(dtr[0] - 191)
		if len(dtr) > int(dtr[0] - 191) {
			err := errors.New("superflours")
			fmt.Println(err)
			return nil
		}
		return &Glist{dat: _Unserialize(dtr[1 : ]), typeId: 2}
	}else {
		// dlen = truelen + 1
		//must be uint32, but int for convenience
		dlen := int(dtr[0]) - 246
		tlen := decodelength(dtr[1 : dlen])
		if len(dtr) > tlen + dlen {
			err := errors.New("superflours")
			fmt.Println(err)
			return nil
		}
		return &Glist{dat: _Unserialize(dtr[dlen : ]), typeId: 2}
	}
}
func decodelength(dtr []byte) int {
	var len int
	for _, t := range dtr {
		len = (len<<4) | int(t)
	}
	return len
}
func PrintList(g *Glist){
	if g == nil {
		fmt.Print("[]")
		return ;
	}
	switch g.typeId {
		case 1:{
			fmt.Print(g.dat.([]byte))
			break ;
		}
		case 2:{
			fmt.Print("[")
			for i, v := range(g.dat.([]Atom)) {
				if i != 0 {
					fmt.Print(",")
				}
				PrintList(v.(*Glist))
			}
			fmt.Print("]")
			break;
		}
		default :{
			break ;
		}
	}
}
func PrintListInString(g *Glist){
	if g == nil {
		fmt.Print("~")
		return ;
	}
	switch g.typeId {
		case 1:{
			fmt.Print("\"0x"+hex.EncodeToString(g.dat.([]byte))+"\"")
			break ;
		}
		case 2:{
			fmt.Print("[")
			for i, v := range(g.dat.([]Atom)) {
				if i != 0 {
					fmt.Print(",")
				}
				PrintListInString(v.(*Glist))
			}
			fmt.Print("]")
			break;
		}
		default :{
			break ;
		}
	}
}
func (g *Glist) Get(ref int) *Glist {
	return g.dat.([]Atom)[ref].(*Glist)
}
func (g *Glist) AsBytes() []byte {
	return g.dat.([]byte)
}
func (g *Glist) AsString() string {
	return hex.EncodeToString(g.dat.([]byte))
}
func (g *Glist) Length() int {
	if g.typeId == 1 {
		return len(g.dat.([]byte))
	}else if g.typeId == 2 {
		return len(g.dat.([]Atom))
	}else {
		return -1
	}
}
func main(){}

下面是用go-leveldb连接到"/geth/chaindata"数据库完成verifyproof的主文件

//link to Goleveldb
package main

import (
	"github.com/syndtr/goleveldb/leveldb"
	"fmt"
	"errors"
	"./rlp"
)

const EDB_PATH = "D:/Go Ethereum/data/geth/chaindata"


var (
	//Got LastHeader
	headHeaderKey = []byte("LastHeader")
	//Got LastBlock
	headBlockKey = []byte("LastBlock")
	//Got a BlockHeader
	headerPrefix = []byte("h")
)

//Hash byte-Array's length
const HashLength = 32

//char maps to bit integer
var hexmaps [128]uint64

//common.Hash
type Hash [HashLength]byte

func (h Hash) bytes() []byte { return h[ : ] }

//TODO - iterator
func checkAll(db *leveldb.DB){
	iter := db.NewIterator(nil, nil)
	for iter.Next(){
		key   := iter.Key()
		value := iter.Value()
		fmt.Println([]byte(key),[]byte(value))
	}
}

//unint64(8-bytes) to bytes
func uint64toslice(number uint64) []byte {
	enc := make([]byte, 8)
	for idx := uint64(0); idx < 8; idx++ {
		enc[7 - idx] = byte((number >> (idx << 3) ) & 0xff)
	}
	//fmt.Println(enc);
	return enc
}

//input a string and return common.Hash
func stringtohash(hashstr string) Hash {
	var hres Hash
	ofs := uint64(0)
	if hashstr[1] == 'x' {
		ofs = 1
	}
	for idx	:= uint64(0); idx < 32; idx++ {
		hres[idx] |= byte(hexmaps[hashstr[ (idx + ofs) << 1     ]] << 4)
		hres[idx] |= byte(hexmaps[hashstr[((idx + ofs) << 1) | 1]])
	}
	return hres
}

//input a string and return common.Hash
func stringtobytes(bytes string) []byte {
	glen := len(bytes)
	if  glen <= 1 || ((glen & 1) == 1) {
		return nil
	}
	glen >>= 1
	bres ,ofs := make([]byte, glen, glen), 0
	if bytes[1] == 'x' {
		ofs = 2
	}
	for idx := int(ofs); idx < glen; idx++ {
		bres[idx] |= byte(hexmaps[bytes[(idx + ofs) << 1 ]] << 4)
		bres[idx] |= byte(hexmaps[bytes[(idx + ofs) << 1 | 1]])
	}
	return bres
}

func stringtoheaderkey(number uint64, hashstr string) []byte {
	return append(append(headerPrefix, uint64toslice(number)...), stringtohash(hashstr).bytes()...);
}

func Cook(db *leveldb.DB, query []byte) ([]byte, error) {
	binfo, err := db.Get(query, nil)
	if err == nil {
		return binfo, nil
	}else {
		return nil, err
	}
}

func findPath(db *leveldb.DB, rootHashStr string, key []byte) ([]byte, error) {
	roothash := stringtohash(rootHashStr)
	querynode, err := Cook(db, roothash[ : ])
	if err != nil {
		return nil, err
	}else {
		if len(key) == 0 {
			return querynode, nil
		}
		node := rlp.Unserialize(querynode)
		switch node.Length() {
			case 2: {
				if len(key) < len(node.Get(0).AsBytes()) || Compare(key, node.Get(0).AsBytes()) != 0 {
					return nil, errors.New("No exists")
				}
				return findPath(db, node.Get(1).AsString(), key[len(node.Get(0).AsBytes()) : ])
				break ;
			}
			case 17: {
				tryquery := node.Get(int(key[0])).AsString()
				if len(tryquery) == 64 {
					return findPath(db, tryquery, key[1 : ])
				}else{
					err = errors.New("No exists")
					return nil, err
				}
				break ;
			}
			default: {
				err := errors.New("Unknown node types")
				return nil, err
			}
		}
	}
	err = errors.New("Impossible approach")
	return nil, err
}
func VerifyProof(db *leveldb.DB, rootHashStr string, key []byte) {
	toval, err := findPath(db, rootHashStr, key)
	if err != nil {
		fmt.Println(err)
	}else {
		rlp.PrintListInString(rlp.Unserialize(toval))
	}
}

func init() {
	for idx := '0'; idx <= '9'; idx++ {
		hexmaps[idx] = uint64(idx - '0')
	}
	for idx := 'a'; idx <= 'f'; idx++ {
		hexmaps[idx] = uint64(idx - 'a' + 10)
	}
	for idx := 'A'; idx <= 'F'; idx++ {
		hexmaps[idx] = uint64(idx - 'A' + 10)
	}
}

func main() {
	StorageHash := "0x11e91152ab237ceff29728c03999ef2debadd7db0fc45b280657c6f7cc4c1ffa"
	StoragePath := append(make([]byte,0), 2, 9)
	db, err := leveldb.OpenFile(EDB_PATH, nil)
	if err != nil {
		fmt.Println("link error")
		fmt.Println(err)
	}else {
		defer db.Close()
		//fmt.Println(StorageHash,StoragePath)
		VerifyProof(db, StorageHash, StoragePath)
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值