Commit cfe8db8f authored by vipwzw's avatar vipwzw Committed by 33cn

update chain33

parent fa8f3f88
...@@ -117,7 +117,7 @@ fmt: fmt_proto fmt_shell ## go fmt ...@@ -117,7 +117,7 @@ fmt: fmt_proto fmt_shell ## go fmt
.PHONY: fmt_proto fmt_shell .PHONY: fmt_proto fmt_shell
fmt_proto: ## go fmt protobuf file fmt_proto: ## go fmt protobuf file
#@find . -name '*.proto' -not -path "./vendor/*" | xargs clang-format -i @find . -name '*.proto' -not -path "./vendor/*" | xargs clang-format -i
fmt_shell: ## check shell file fmt_shell: ## check shell file
find . -name '*.sh' -not -path "./vendor/*" | xargs shfmt -w -s -i 4 -ci -bn find . -name '*.sh' -not -path "./vendor/*" | xargs shfmt -w -s -i 4 -ci -bn
......
...@@ -47,6 +47,7 @@ func GetLocalDBKeyList() [][]byte { ...@@ -47,6 +47,7 @@ func GetLocalDBKeyList() [][]byte {
return [][]byte{ return [][]byte{
blockLastHeight, bodyPerfix, LastSequence, headerPerfix, heightToHeaderPerfix, blockLastHeight, bodyPerfix, LastSequence, headerPerfix, heightToHeaderPerfix,
hashPerfix, tdPerfix, heightToHashKeyPerfix, seqToHashKey, HashToSeqPerfix, hashPerfix, tdPerfix, heightToHashKeyPerfix, seqToHashKey, HashToSeqPerfix,
seqCBPrefix, seqCBLastNumPrefix,
} }
} }
...@@ -1057,3 +1058,49 @@ func (bs *BlockStore) SetUpgradeMeta(meta *types.UpgradeMeta) error { ...@@ -1057,3 +1058,49 @@ func (bs *BlockStore) SetUpgradeMeta(meta *types.UpgradeMeta) error {
storeLog.Info("SetUpgradeMeta", "meta", meta) storeLog.Info("SetUpgradeMeta", "meta", meta)
return bs.db.SetSync(version.LocalDBMeta, verByte) return bs.db.SetSync(version.LocalDBMeta, verByte)
} }
//isRecordBlockSequence配置的合法性检测
func (bs *BlockStore) isRecordBlockSequenceValid() {
storeLog.Error("isRecordBlockSequenceValid")
lastHeight := bs.Height()
lastSequence, err := bs.LoadBlockLastSequence()
if err != nil {
if err != types.ErrHeightNotExist {
storeLog.Error("isRecordBlockSequenceValid", "LoadBlockLastSequence err", err)
panic(err)
}
}
//使能isRecordBlockSequence时的检测
if isRecordBlockSequence {
//中途开启isRecordBlockSequence报错
if lastSequence == -1 && lastHeight != -1 {
storeLog.Error("isRecordBlockSequenceValid", "lastHeight", lastHeight, "lastSequence", lastSequence)
panic("isRecordBlockSequence is true must Synchronizing data from zero block")
}
//lastSequence 必须大于等于lastheight
if lastHeight > lastSequence {
storeLog.Error("isRecordBlockSequenceValid", "lastHeight", lastHeight, "lastSequence", lastSequence)
panic("lastSequence must greater than or equal to lastHeight")
}
//通过lastSequence获取对应的blockhash != lastHeader.hash 报错
if lastSequence != -1 {
blockSequence, err := bs.GetBlockSequence(lastSequence)
if err != nil {
storeLog.Error("isRecordBlockSequenceValid", "lastSequence", lastSequence, "GetBlockSequence err", err)
panic(err)
}
lastHeader := bs.LastHeader()
if !bytes.Equal(lastHeader.Hash, blockSequence.Hash) {
storeLog.Error("isRecordBlockSequenceValid:", "lastHeight", lastHeight, "lastSequence", lastSequence, "lastHeader.Hash", common.ToHex(lastHeader.Hash), "blockSequence.Hash", common.ToHex(blockSequence.Hash))
panic("The hash values of lastSequence and lastHeight are different.")
}
}
return
}
//去使能isRecordBlockSequence时的检测
if lastSequence != -1 {
storeLog.Error("isRecordBlockSequenceValid", "lastSequence", lastSequence)
panic("can not disable isRecordBlockSequence")
}
}
...@@ -222,6 +222,10 @@ func (chain *BlockChain) GetOrphanPool() *OrphanPool { ...@@ -222,6 +222,10 @@ func (chain *BlockChain) GetOrphanPool() *OrphanPool {
//InitBlockChain 区块链初始化 //InitBlockChain 区块链初始化
func (chain *BlockChain) InitBlockChain() { func (chain *BlockChain) InitBlockChain() {
//isRecordBlockSequence配置的合法性检测
if !chain.cfg.IsParaChain {
chain.blockStore.isRecordBlockSequenceValid()
}
//先缓存最新的128个block信息到cache中 //先缓存最新的128个block信息到cache中
curheight := chain.GetBlockHeight() curheight := chain.GetBlockHeight()
if types.IsEnable("TxHeight") { if types.IsEnable("TxHeight") {
...@@ -402,9 +406,10 @@ func (chain *BlockChain) InitIndexAndBestView() { ...@@ -402,9 +406,10 @@ func (chain *BlockChain) InitIndexAndBestView() {
height = 0 height = 0
} }
for ; height <= curheight; height++ { for ; height <= curheight; height++ {
header, _ := chain.blockStore.GetBlockHeaderByHeight(height) header, err := chain.blockStore.GetBlockHeaderByHeight(height)
if header == nil { if header == nil {
return chainlog.Error("InitIndexAndBestView GetBlockHeaderByHeight", "height", height, "err", err)
panic("InitIndexAndBestView fail!")
} }
newNode := newBlockNodeByHeader(false, header, "self", -1) newNode := newBlockNodeByHeader(false, header, "self", -1)
......
...@@ -93,6 +93,9 @@ func (chain *BlockChain) ProcAddBlockSeqCB(cb *types.BlockSeqCB) error { ...@@ -93,6 +93,9 @@ func (chain *BlockChain) ProcAddBlockSeqCB(cb *types.BlockSeqCB) error {
return types.ErrInvalidParam return types.ErrInvalidParam
} }
if !isRecordBlockSequence {
return types.ErrRecordBlockSequence
}
if chain.blockStore.seqCBNum() >= MaxSeqCB && !chain.blockStore.isSeqCBExist(cb.Name) { if chain.blockStore.seqCBNum() >= MaxSeqCB && !chain.blockStore.isSeqCBExist(cb.Name) {
return types.ErrTooManySeqCB return types.ErrTooManySeqCB
} }
......
...@@ -2,9 +2,6 @@ ...@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
/*
Package commands 扫描chain33项目下plugin中所有的插件,根据扫描到的结果重新更新共识、执行器和数据操作的初始化文件 init.go
*/
package commands package commands
import ( import (
...@@ -19,7 +16,7 @@ import ( ...@@ -19,7 +16,7 @@ import (
func UpdateInitCmd() *cobra.Command { func UpdateInitCmd() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "updateinit", Use: "updateinit",
Short: "Update chain33 plugin consensus、dapp、store init.go file", Short: "Update chain33 plugin consensus、dapp、store、mempool init.go file",
Run: updateInit, Run: updateInit,
} }
cmd.Flags().StringP("path", "p", "plugin", "path of plugin") cmd.Flags().StringP("path", "p", "plugin", "path of plugin")
......
# type字段仅支持 consensus dapp store # type字段仅支持 consensus dapp store mempool
[blackwhite] [mempool-price]
type = "dapp" type = "mempool"
gitrepo = "gitlab.33.cn/sanghg/blackwhite" gitrepo = "github.com/33cn/plugin/plugin/mempool/price"
version="" version=""
syntax = "proto3";
package accounts;
message DemoAction {
oneof value {
DemoCreate create = 1;
DemoRun play = 2;
DemoClose show = 3;
}
int32 ty = 6;
}
message DemoCreate {
[ consensus - ticket ] string name = 1;
}
message DemoRun {
string name = 1;
}
message DemoClose {
string name = 1;
}
\ No newline at end of file
...@@ -51,5 +51,11 @@ Package main chain33开发者工具,主要提供以下功能: ...@@ -51,5 +51,11 @@ Package main chain33开发者工具,主要提供以下功能:
-n --name 执行器的项目名和类名,必填参数 -n --name 执行器的项目名和类名,必填参数
-p --propfile 导入执行器类型的proto3协议模板,如果不填默认为config/执行器名称.proto -p --propfile 导入执行器类型的proto3协议模板,如果不填默认为config/执行器名称.proto
-t --templatepath 生成执行器项目的模板文件,不填默认为config/template下的所有文件 -t --templatepath 生成执行器项目的模板文件,不填默认为config/template下的所有文件
更新初始化文件:
扫描指定path目录下所有的插件,根据扫描到的结果重新更新consensus、dapp和、store、mempool的初始化文件 init.go
使用方式:./tools updateinit -p $(YourPluginPath)
例子:./tools updateinit -p /GOPATH/src/github.com/33cn/chain33/cmd/tools/plugin
*/ */
package main package main
...@@ -295,6 +295,7 @@ clean: ...@@ -295,6 +295,7 @@ clean:
@rm -rf plugin/dapp/init @rm -rf plugin/dapp/init
@rm -rf plugin/crypto/init @rm -rf plugin/crypto/init
@rm -rf plugin/store/init @rm -rf plugin/store/init
@rm -rf plugin/mempool/init
` `
// 生成 .travis.yml 文件模板 // 生成 .travis.yml 文件模板
...@@ -308,7 +309,7 @@ go: ...@@ -308,7 +309,7 @@ go:
// 生成 plugin/plugin.toml的文件模板 // 生成 plugin/plugin.toml的文件模板
CpftPluginToml = ` CpftPluginToml = `
# type字段仅支持 consensus dapp store # type字段仅支持 consensus dapp store mempool
[dapp-ticket] [dapp-ticket]
gitrepo = "github.com/33cn/plugin/plugin/dapp/ticket" gitrepo = "github.com/33cn/plugin/plugin/dapp/ticket"
...@@ -326,6 +327,12 @@ gitrepo = "github.com/33cn/plugin/plugin/dapp/token" ...@@ -326,6 +327,12 @@ gitrepo = "github.com/33cn/plugin/plugin/dapp/token"
[dapp-trade] [dapp-trade]
gitrepo = "github.com/33cn/plugin/plugin/dapp/trade" gitrepo = "github.com/33cn/plugin/plugin/dapp/trade"
[mempool-price]
gitrepo = "github.com/33cn/plugin/plugin/mempool/price"
[mempool-score]
gitrepo = "github.com/33cn/plugin/plugin/mempool/score"
` `
// 项目 cli/main.go 文件模板 // 项目 cli/main.go 文件模板
CpftCliMain = `package main CpftCliMain = `package main
......
...@@ -23,6 +23,7 @@ const ( ...@@ -23,6 +23,7 @@ const (
consensusFolderName = "consensus" consensusFolderName = "consensus"
storeFolderName = "store" storeFolderName = "store"
cryptoFolderName = "crypto" cryptoFolderName = "crypto"
mempoolFolderName = "mempool"
) )
type pluginConfigItem struct { type pluginConfigItem struct {
...@@ -91,6 +92,7 @@ func (im *importPackageStrategy) initData() error { ...@@ -91,6 +92,7 @@ func (im *importPackageStrategy) initData() error {
consensusItems := make([]*pluginItem, 0) consensusItems := make([]*pluginItem, 0)
storeItems := make([]*pluginItem, 0) storeItems := make([]*pluginItem, 0)
cryptoItems := make([]*pluginItem, 0) cryptoItems := make([]*pluginItem, 0)
mempoolItems := make([]*pluginItem, 0)
//read current plugin dir //read current plugin dir
//(分成两级,并且去掉了 init 目录) //(分成两级,并且去掉了 init 目录)
...@@ -141,6 +143,8 @@ func (im *importPackageStrategy) initData() error { ...@@ -141,6 +143,8 @@ func (im *importPackageStrategy) initData() error {
storeItems = append(storeItems, item) storeItems = append(storeItems, item)
case cryptoFolderName: case cryptoFolderName:
cryptoItems = append(cryptoItems, item) cryptoItems = append(cryptoItems, item)
case mempoolFolderName:
mempoolItems = append(mempoolItems, item)
default: default:
fmt.Printf("type %s is not supported.\n", cfgItem.Type) fmt.Printf("type %s is not supported.\n", cfgItem.Type)
return errors.New("config error") return errors.New("config error")
...@@ -150,6 +154,7 @@ func (im *importPackageStrategy) initData() error { ...@@ -150,6 +154,7 @@ func (im *importPackageStrategy) initData() error {
im.items[consensusFolderName] = consensusItems im.items[consensusFolderName] = consensusItems
im.items[storeFolderName] = storeItems im.items[storeFolderName] = storeItems
im.items[cryptoFolderName] = cryptoItems im.items[cryptoFolderName] = cryptoItems
im.items[mempoolFolderName] = mempoolItems
im.projRootPath = "" im.projRootPath = ""
im.projPluginPath, _ = im.getParam("path") im.projPluginPath, _ = im.getParam("path")
return nil return nil
...@@ -201,11 +206,11 @@ func (im *importPackageStrategy) generateImportFile() error { ...@@ -201,11 +206,11 @@ func (im *importPackageStrategy) generateImportFile() error {
importStrs := map[string]string{} importStrs := map[string]string{}
for name, plugins := range im.items { for name, plugins := range im.items {
for _, item := range plugins { for _, item := range plugins {
importStrs[name] += fmt.Sprintf("\r\n_ \"%s\" //auto gen", item.gitRepo) importStrs[name] += fmt.Sprintf("\n_ \"%s\" //auto gen", item.gitRepo)
} }
} }
for key, value := range importStrs { for key, value := range importStrs {
content := fmt.Sprintf("package init\r\n\r\nimport(%s\r\n)", value) content := fmt.Sprintf("package init\n\nimport(%s\n)", value)
initFile := fmt.Sprintf("%s/%s/init/init.go", im.projPluginPath, key) initFile := fmt.Sprintf("%s/%s/init/init.go", im.projPluginPath, key)
util.MakeDir(initFile) util.MakeDir(initFile)
......
...@@ -11,16 +11,18 @@ import ( ...@@ -11,16 +11,18 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"github.com/33cn/chain33/cmd/tools/tasks" "github.com/33cn/chain33/cmd/tools/tasks"
) )
type updateInitStrategy struct { type updateInitStrategy struct {
strategyBasic strategyBasic
consRootPath string consRootPath string
dappRootPath string dappRootPath string
storeRootPath string storeRootPath string
cryptoRootPath string cryptoRootPath string
mempoolRootPath string
} }
func (up *updateInitStrategy) Run() error { func (up *updateInitStrategy) Run() error {
...@@ -35,12 +37,15 @@ func (up *updateInitStrategy) Run() error { ...@@ -35,12 +37,15 @@ func (up *updateInitStrategy) Run() error {
func (up *updateInitStrategy) initMember() error { func (up *updateInitStrategy) initMember() error {
path, err := up.getParam("path") path, err := up.getParam("path")
packname, _ := up.getParam("packname") packname, _ := up.getParam("packname")
gopath := os.Getenv("GOPATH")
if err != nil || path == "" { if err != nil || path == "" {
gopath := os.Getenv("GOPATH")
if len(gopath) > 0 { if len(gopath) > 0 {
path = filepath.Join(gopath, "/src/github.com/33cn/chain33/plugin/") path = filepath.Join(gopath, "/src/github.com/33cn/chain33/plugin/")
} }
} }
if packname == "" {
packname = strings.Replace(path, gopath+"/src/", "", 1)
}
if len(path) == 0 { if len(path) == 0 {
return errors.New("Chain33 Plugin Not Existed") return errors.New("Chain33 Plugin Not Existed")
} }
...@@ -48,10 +53,12 @@ func (up *updateInitStrategy) initMember() error { ...@@ -48,10 +53,12 @@ func (up *updateInitStrategy) initMember() error {
up.dappRootPath = fmt.Sprintf("%s/dapp/", path) up.dappRootPath = fmt.Sprintf("%s/dapp/", path)
up.storeRootPath = fmt.Sprintf("%s/store/", path) up.storeRootPath = fmt.Sprintf("%s/store/", path)
up.cryptoRootPath = fmt.Sprintf("%s/crypto/", path) up.cryptoRootPath = fmt.Sprintf("%s/crypto/", path)
up.mempoolRootPath = fmt.Sprintf("%s/mempool/", path)
mkdir(up.consRootPath) mkdir(up.consRootPath)
mkdir(up.dappRootPath) mkdir(up.dappRootPath)
mkdir(up.storeRootPath) mkdir(up.storeRootPath)
mkdir(up.cryptoRootPath) mkdir(up.cryptoRootPath)
mkdir(up.mempoolRootPath)
buildInit(path, packname) buildInit(path, packname)
return nil return nil
} }
...@@ -76,7 +83,9 @@ import ( ...@@ -76,7 +83,9 @@ import (
_ "${packname}/crypto/init" //crypto init _ "${packname}/crypto/init" //crypto init
_ "${packname}/dapp/init" //dapp init _ "${packname}/dapp/init" //dapp init
_ "${packname}/store/init" //store init _ "${packname}/store/init" //store init
)`) _ "${packname}/mempool/init" //mempool init
)
`)
data = bytes.Replace(data, []byte("${packname}"), []byte(packname), -1) data = bytes.Replace(data, []byte("${packname}"), []byte(packname), -1)
ioutil.WriteFile(path, data, 0666) ioutil.WriteFile(path, data, 0666)
} }
...@@ -114,6 +123,9 @@ func (up *updateInitStrategy) buildTask() tasks.Task { ...@@ -114,6 +123,9 @@ func (up *updateInitStrategy) buildTask() tasks.Task {
&tasks.UpdateInitFileTask{ &tasks.UpdateInitFileTask{
Folder: up.cryptoRootPath, Folder: up.cryptoRootPath,
}, },
&tasks.UpdateInitFileTask{
Folder: up.mempoolRootPath,
},
) )
task := taskSlice[0] task := taskSlice[0]
......
...@@ -183,11 +183,11 @@ func (c *CreateDappSourceTask) createExecDelLocalFile() error { ...@@ -183,11 +183,11 @@ func (c *CreateDappSourceTask) createExecDelLocalFile() error {
// 组成规则是 TyLog+ActionName + ActionMemberName // 组成规则是 TyLog+ActionName + ActionMemberName
func (c *CreateDappSourceTask) buildActionLogTypeText() (text string, err error) { func (c *CreateDappSourceTask) buildActionLogTypeText() (text string, err error) {
items := fmt.Sprintf("TyLog%sUnknown = iota\r\n", c.ExecuteName) items := fmt.Sprintf("TyLog%sUnknown = iota\n", c.ExecuteName)
for _, info := range c.actionInfos { for _, info := range c.actionInfos {
items += fmt.Sprintf("TyLog%s%s\r\n", c.ExecuteName, info.memberName) items += fmt.Sprintf("TyLog%s%s\n", c.ExecuteName, info.memberName)
} }
text = fmt.Sprintf("const (\r\n%s)\r\n", items) text = fmt.Sprintf("const (\n%s)\n", items)
return return
} }
...@@ -195,9 +195,9 @@ func (c *CreateDappSourceTask) buildActionLogTypeText() (text string, err error) ...@@ -195,9 +195,9 @@ func (c *CreateDappSourceTask) buildActionLogTypeText() (text string, err error)
func (c *CreateDappSourceTask) buildActionIDText() (text string, err error) { func (c *CreateDappSourceTask) buildActionIDText() (text string, err error) {
var items string var items string
for index, info := range c.actionInfos { for index, info := range c.actionInfos {
items += fmt.Sprintf("%sAction%s = %d\r\n", c.ExecuteName, info.memberName, index) items += fmt.Sprintf("%sAction%s = %d\n", c.ExecuteName, info.memberName, index)
} }
text = fmt.Sprintf("const (\r\n%s)\r\n", items) text = fmt.Sprintf("const (\n%s)\n", items)
return return
} }
...@@ -205,15 +205,15 @@ func (c *CreateDappSourceTask) buildActionIDText() (text string, err error) { ...@@ -205,15 +205,15 @@ func (c *CreateDappSourceTask) buildActionIDText() (text string, err error) {
func (c *CreateDappSourceTask) buildLogMapText() (text string, err error) { func (c *CreateDappSourceTask) buildLogMapText() (text string, err error) {
var items string var items string
for _, info := range c.actionInfos { for _, info := range c.actionInfos {
items += fmt.Sprintf("\"%s\": %sAction%s,\r\n", info.memberName, c.ExecuteName, info.memberName) items += fmt.Sprintf("\"%s\": %sAction%s,\n", info.memberName, c.ExecuteName, info.memberName)
} }
text = fmt.Sprintf("map[string]int32{\r\n%s}", items) text = fmt.Sprintf("map[string]int32{\n%s}", items)
return return
} }
// 返回 map[string]*types.LogInfo // 返回 map[string]*types.LogInfo
func (c *CreateDappSourceTask) buidTypeMapText() (text string, err error) { func (c *CreateDappSourceTask) buidTypeMapText() (text string, err error) {
text = fmt.Sprintf("map[int64]*types.LogInfo{\r\n}") text = fmt.Sprintf("map[int64]*types.LogInfo{\n}")
return return
} }
......
...@@ -7,7 +7,10 @@ package tasks ...@@ -7,7 +7,10 @@ package tasks
import ( import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os"
"os/exec" "os/exec"
"strings"
"github.com/33cn/chain33/util" "github.com/33cn/chain33/util"
) )
...@@ -54,6 +57,17 @@ func (up *UpdateInitFileTask) Execute() error { ...@@ -54,6 +57,17 @@ func (up *UpdateInitFileTask) Execute() error {
func (up *UpdateInitFileTask) init() error { func (up *UpdateInitFileTask) init() error {
up.initFile = fmt.Sprintf("%sinit/init.go", up.Folder) up.initFile = fmt.Sprintf("%sinit/init.go", up.Folder)
up.itemDatas = make([]*itemData, 0) up.itemDatas = make([]*itemData, 0)
gopath := os.Getenv("GOPATH")
if len(gopath) == 0 {
return errors.New("GOPATH Not Existed")
}
// 获取所有文件
files, _ := ioutil.ReadDir(up.Folder)
for _, file := range files {
if file.IsDir() && file.Name() != "init" {
up.itemDatas = append(up.itemDatas, &itemData{strings.Replace(up.Folder, gopath+"/src/", "", 1) + file.Name()})
}
}
return nil return nil
} }
...@@ -63,9 +77,9 @@ func (up *UpdateInitFileTask) genInitFile() error { ...@@ -63,9 +77,9 @@ func (up *UpdateInitFileTask) genInitFile() error {
} }
var importStr, content string var importStr, content string
for _, item := range up.itemDatas { for _, item := range up.itemDatas {
importStr += fmt.Sprintf("_ \"%s\"\r\n", item.path) importStr += fmt.Sprintf("_ \"%s\"\n", item.path)
} }
content = fmt.Sprintf("package init \r\n\r\nimport (\r\n%s)", importStr) content = fmt.Sprintf("package init \n\nimport (\n%s)\n", importStr)
util.DeleteFile(up.initFile) util.DeleteFile(up.initFile)
_, err := util.WriteStringToFile(up.initFile, content) _, err := util.WriteStringToFile(up.initFile, content)
......
...@@ -85,7 +85,8 @@ type Batch interface { ...@@ -85,7 +85,8 @@ type Batch interface {
Set(key, value []byte) Set(key, value []byte)
Delete(key []byte) Delete(key []byte)
Write() error Write() error
ValueSize() int // amount of data in the batch ValueSize() int // size of data in the batch
ValueLen() int // amount of data in the batch
Reset() // Reset resets the batch for reuse Reset() // Reset resets the batch for reuse
} }
......
...@@ -279,24 +279,28 @@ type GoBadgerDBBatch struct { ...@@ -279,24 +279,28 @@ type GoBadgerDBBatch struct {
batch *badger.Txn batch *badger.Txn
//wop *opt.WriteOptions //wop *opt.WriteOptions
size int size int
len int
} }
//NewBatch new //NewBatch new
func (db *GoBadgerDB) NewBatch(sync bool) Batch { func (db *GoBadgerDB) NewBatch(sync bool) Batch {
batch := db.db.NewTransaction(true) batch := db.db.NewTransaction(true)
return &GoBadgerDBBatch{db, batch, 0} return &GoBadgerDBBatch{db, batch, 0, 0}
} }
//Set set //Set set
func (mBatch *GoBadgerDBBatch) Set(key, value []byte) { func (mBatch *GoBadgerDBBatch) Set(key, value []byte) {
mBatch.batch.Set(key, value) mBatch.batch.Set(key, value)
mBatch.size += len(value) mBatch.size += len(value)
mBatch.size += len(key)
mBatch.len += len(value)
} }
//Delete 设置 //Delete 设置
func (mBatch *GoBadgerDBBatch) Delete(key []byte) { func (mBatch *GoBadgerDBBatch) Delete(key []byte) {
mBatch.batch.Delete(key) mBatch.batch.Delete(key)
mBatch.size++ mBatch.size += len(key)
mBatch.len++
} }
//Write 写入 //Write 写入
...@@ -315,10 +319,16 @@ func (mBatch *GoBadgerDBBatch) ValueSize() int { ...@@ -315,10 +319,16 @@ func (mBatch *GoBadgerDBBatch) ValueSize() int {
return mBatch.size return mBatch.size
} }
//ValueLen batch数量
func (mBatch *GoBadgerDBBatch) ValueLen() int {
return mBatch.len
}
//Reset 重置 //Reset 重置
func (mBatch *GoBadgerDBBatch) Reset() { func (mBatch *GoBadgerDBBatch) Reset() {
if nil != mBatch.db && nil != mBatch.db.db { if nil != mBatch.db && nil != mBatch.db.db {
mBatch.batch = mBatch.db.db.NewTransaction(true) mBatch.batch = mBatch.db.db.NewTransaction(true)
} }
mBatch.size = 0 mBatch.size = 0
mBatch.len = 0
} }
...@@ -234,23 +234,27 @@ type goLevelDBBatch struct { ...@@ -234,23 +234,27 @@ type goLevelDBBatch struct {
batch *leveldb.Batch batch *leveldb.Batch
wop *opt.WriteOptions wop *opt.WriteOptions
size int size int
len int
} }
//NewBatch new //NewBatch new
func (db *GoLevelDB) NewBatch(sync bool) Batch { func (db *GoLevelDB) NewBatch(sync bool) Batch {
batch := new(leveldb.Batch) batch := new(leveldb.Batch)
wop := &opt.WriteOptions{Sync: sync} wop := &opt.WriteOptions{Sync: sync}
return &goLevelDBBatch{db, batch, wop, 0} return &goLevelDBBatch{db, batch, wop, 0, 0}
} }
func (mBatch *goLevelDBBatch) Set(key, value []byte) { func (mBatch *goLevelDBBatch) Set(key, value []byte) {
mBatch.batch.Put(key, value) mBatch.batch.Put(key, value)
mBatch.size += len(key)
mBatch.size += len(value) mBatch.size += len(value)
mBatch.len += len(value)
} }
func (mBatch *goLevelDBBatch) Delete(key []byte) { func (mBatch *goLevelDBBatch) Delete(key []byte) {
mBatch.batch.Delete(key) mBatch.batch.Delete(key)
mBatch.size++ mBatch.size += len(key)
mBatch.len++
} }
func (mBatch *goLevelDBBatch) Write() error { func (mBatch *goLevelDBBatch) Write() error {
...@@ -266,7 +270,13 @@ func (mBatch *goLevelDBBatch) ValueSize() int { ...@@ -266,7 +270,13 @@ func (mBatch *goLevelDBBatch) ValueSize() int {
return mBatch.size return mBatch.size
} }
//ValueLen batch数量
func (mBatch *goLevelDBBatch) ValueLen() int {
return mBatch.len
}
func (mBatch *goLevelDBBatch) Reset() { func (mBatch *goLevelDBBatch) Reset() {
mBatch.batch.Reset() mBatch.batch.Reset()
mBatch.len = 0
mBatch.size = 0 mBatch.size = 0
} }
...@@ -253,6 +253,7 @@ type memBatch struct { ...@@ -253,6 +253,7 @@ type memBatch struct {
db *GoMemDB db *GoMemDB
writes []kv writes []kv
size int size int
len int
} }
//NewBatch new //NewBatch new
...@@ -264,11 +265,14 @@ func (b *memBatch) Set(key, value []byte) { ...@@ -264,11 +265,14 @@ func (b *memBatch) Set(key, value []byte) {
//println("-b-", string(key)[0:4], common.ToHex(key)) //println("-b-", string(key)[0:4], common.ToHex(key))
b.writes = append(b.writes, kv{CopyBytes(key), CopyBytes(value)}) b.writes = append(b.writes, kv{CopyBytes(key), CopyBytes(value)})
b.size += len(value) b.size += len(value)
b.size += len(key)
b.len += len(value)
} }
func (b *memBatch) Delete(key []byte) { func (b *memBatch) Delete(key []byte) {
b.writes = append(b.writes, kv{CopyBytes(key), CopyBytes(nil)}) b.writes = append(b.writes, kv{CopyBytes(key), CopyBytes(nil)})
b.size++ b.size += len(key)
b.len++
} }
func (b *memBatch) Write() error { func (b *memBatch) Write() error {
...@@ -291,7 +295,13 @@ func (b *memBatch) ValueSize() int { ...@@ -291,7 +295,13 @@ func (b *memBatch) ValueSize() int {
return b.size return b.size
} }
//ValueLen batch数量
func (b *memBatch) ValueLen() int {
return b.len
}
func (b *memBatch) Reset() { func (b *memBatch) Reset() {
b.writes = b.writes[:0] b.writes = b.writes[:0]
b.size = 0 b.size = 0
b.len = 0
} }
...@@ -456,6 +456,7 @@ type PegasusBatch struct { ...@@ -456,6 +456,7 @@ type PegasusBatch struct {
table pegasus.TableConnector table pegasus.TableConnector
batchset map[string][]byte batchset map[string][]byte
batchdel map[string][]byte batchdel map[string][]byte
size int
} }
//NewBatch new //NewBatch new
...@@ -467,6 +468,8 @@ func (db *PegasusDB) NewBatch(sync bool) Batch { ...@@ -467,6 +468,8 @@ func (db *PegasusDB) NewBatch(sync bool) Batch {
func (db *PegasusBatch) Set(key, value []byte) { func (db *PegasusBatch) Set(key, value []byte) {
db.batchset[string(key)] = value db.batchset[string(key)] = value
delete(db.batchdel, string(key)) delete(db.batchdel, string(key))
db.size += len(value)
db.size += len(key)
} }
//Delete 删除 //Delete 删除
...@@ -474,6 +477,7 @@ func (db *PegasusBatch) Delete(key []byte) { ...@@ -474,6 +477,7 @@ func (db *PegasusBatch) Delete(key []byte) {
db.batchset[string(key)] = []byte("") db.batchset[string(key)] = []byte("")
delete(db.batchset, string(key)) delete(db.batchset, string(key))
db.batchdel[string(key)] = key db.batchdel[string(key)] = key
db.size += len(key)
} }
// 注意本方法的实现逻辑,因为ssdb没有提供删除和更新同时进行的批量操作; // 注意本方法的实现逻辑,因为ssdb没有提供删除和更新同时进行的批量操作;
...@@ -556,6 +560,11 @@ func (db *PegasusBatch) Write() error { ...@@ -556,6 +560,11 @@ func (db *PegasusBatch) Write() error {
//ValueSize value批长度 //ValueSize value批长度
func (db *PegasusBatch) ValueSize() int { func (db *PegasusBatch) ValueSize() int {
return db.size
}
//ValueLen batch数量
func (db *PegasusBatch) ValueLen() int {
return len(db.batchset) return len(db.batchset)
} }
...@@ -563,6 +572,7 @@ func (db *PegasusBatch) ValueSize() int { ...@@ -563,6 +572,7 @@ func (db *PegasusBatch) ValueSize() int {
func (db *PegasusBatch) Reset() { func (db *PegasusBatch) Reset() {
db.batchset = make(map[string][]byte) db.batchset = make(map[string][]byte)
db.batchdel = make(map[string][]byte) db.batchdel = make(map[string][]byte)
db.size = 0
} }
func getHashKey(key []byte) []byte { func getHashKey(key []byte) []byte {
......
...@@ -457,6 +457,7 @@ type ssDBBatch struct { ...@@ -457,6 +457,7 @@ type ssDBBatch struct {
db *GoSSDB db *GoSSDB
batchset map[string][]byte batchset map[string][]byte
batchdel map[string]bool batchdel map[string]bool
size int
} }
//NewBatch new //NewBatch new
...@@ -467,12 +468,15 @@ func (db *GoSSDB) NewBatch(sync bool) Batch { ...@@ -467,12 +468,15 @@ func (db *GoSSDB) NewBatch(sync bool) Batch {
func (db *ssDBBatch) Set(key, value []byte) { func (db *ssDBBatch) Set(key, value []byte) {
db.batchset[string(key)] = value db.batchset[string(key)] = value
delete(db.batchdel, string(key)) delete(db.batchdel, string(key))
db.size += len(value)
db.size += len(key)
} }
func (db *ssDBBatch) Delete(key []byte) { func (db *ssDBBatch) Delete(key []byte) {
db.batchset[string(key)] = []byte{} db.batchset[string(key)] = []byte{}
delete(db.batchset, string(key)) delete(db.batchset, string(key))
db.batchdel[string(key)] = true db.batchdel[string(key)] = true
db.size += len(key)
} }
// 注意本方法的实现逻辑,因为ssdb没有提供删除和更新同时进行的批量操作; // 注意本方法的实现逻辑,因为ssdb没有提供删除和更新同时进行的批量操作;
...@@ -507,10 +511,16 @@ func (db *ssDBBatch) Write() error { ...@@ -507,10 +511,16 @@ func (db *ssDBBatch) Write() error {
} }
func (db *ssDBBatch) ValueSize() int { func (db *ssDBBatch) ValueSize() int {
return db.size
}
//ValueLen batch数量
func (db *ssDBBatch) ValueLen() int {
return len(db.batchset) return len(db.batchset)
} }
func (db *ssDBBatch) Reset() { func (db *ssDBBatch) Reset() {
db.batchset = make(map[string][]byte) db.batchset = make(map[string][]byte)
db.batchdel = make(map[string]bool) db.batchdel = make(map[string]bool)
db.size = 0
} }
...@@ -22,7 +22,7 @@ type Count struct { ...@@ -22,7 +22,7 @@ type Count struct {
//NewCount 创建一个计数器 //NewCount 创建一个计数器
func NewCount(prefix string, name string, kvdb db.KV) *Count { func NewCount(prefix string, name string, kvdb db.KV) *Count {
keydata := []byte(prefix + "#" + name) keydata := []byte(prefix + sep + name)
return &Count{ return &Count{
prefix: prefix, prefix: prefix,
name: name, name: name,
......
...@@ -14,4 +14,5 @@ var ( ...@@ -14,4 +14,5 @@ var (
ErrTooManyIndex = errors.New("ErrTooManyIndex") ErrTooManyIndex = errors.New("ErrTooManyIndex")
ErrTablePrefixOrTableName = errors.New("ErrTablePrefixOrTableName") ErrTablePrefixOrTableName = errors.New("ErrTablePrefixOrTableName")
ErrDupPrimaryKey = errors.New("ErrDupPrimaryKey") ErrDupPrimaryKey = errors.New("ErrDupPrimaryKey")
ErrNilValue = errors.New("ErrNilValue")
) )
package table
import (
"errors"
"strings"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
)
var tablelog = log15.New("module", "db.table")
/*
设计表的联查:
我们不可能做到数据库这样强大的功能,但是联查功能几乎是不可能绕过的功能。
table1:
[gameId, status]
table2:
[txhash, gameId, addr]
他们都独立的构造, 与更新
如果设置了两个表的: join, 比如: addr & status 要作为一个查询key, 那么我们需要维护一个:
join_table2_table1:
//table2 primary key
//table1 primary key
//addr_status 的一个关联index
[txhash, gameId, addr_status]
能够join的前提:
table2 包含 table1 的primary key
数据更新:
table1 数据更新 自动触发: join_table2_table1 更新 addr & status
table2 数据更新 也会自动触发: join_table2_table1 更新 addr & status
例子:
table1 更新了 gameId 对应 status -> 触发 join_table2_table1 所有对应 gameId 更新 addr & status
table2 更新了 txhash 对应的 addr -> 触发 join_table2_table1 所有对应的 txhash 对应的 addr & status
注意 join_table2_table1 是自动维护的
table2 中自动可以查询 addr & status 这个index
*/
//JoinTable 是由两个表格组合成的一个表格,自动维护一个联合结构
//其中主表: LeftTable
//连接表: RightTable
type JoinTable struct {
left *Table
right *Table
*Table
Fk string
leftIndex []string
rightIndex []string
}
//NewJoinTable 新建一个JoinTable
func NewJoinTable(left *Table, right *Table, indexes []string) (*JoinTable, error) {
if left.kvdb != right.kvdb {
return nil, errors.New("jointable: kvdb must same")
}
if _, ok := left.kvdb.(db.KVDB); !ok {
return nil, errors.New("jointable: kvdb must be db.KVDB")
}
if left.opt.Prefix != right.opt.Prefix {
return nil, errors.New("jointable: left and right table prefix must same")
}
fk := right.opt.Primary
if !left.canGet(fk) {
return nil, errors.New("jointable: left must has right primary index")
}
join := &JoinTable{left: left, right: right, Fk: fk}
for _, index := range indexes {
joinindex := strings.Split(index, joinsep)
if len(joinindex) != 2 {
return nil, errors.New("jointable: index config error")
}
if joinindex[0] != "" && !left.canGet(joinindex[0]) {
return nil, errors.New("jointable: left table can not get: " + joinindex[0])
}
if joinindex[0] != "" {
join.leftIndex = append(join.leftIndex, joinindex[0])
}
if joinindex[1] == "" || !right.canGet(joinindex[1]) {
return nil, errors.New("jointable: left table can not get: " + joinindex[1])
}
if joinindex[1] != "" {
join.rightIndex = append(join.rightIndex, joinindex[1])
}
}
opt := &Option{
Join: true,
Prefix: left.opt.Prefix,
Name: left.opt.Name + joinsep + right.opt.Name,
Primary: left.opt.Primary,
Index: indexes,
}
mytable, err := NewTable(&JoinMeta{
left: left.meta,
right: right.meta}, left.kvdb, opt)
if err != nil {
return nil, err
}
join.Table = mytable
return join, nil
}
//GetLeft get left table
func (join *JoinTable) GetLeft() *Table {
return join.left
}
//GetRight get right table
func (join *JoinTable) GetRight() *Table {
return join.right
}
//GetTable get table by name
func (join *JoinTable) GetTable(name string) (*Table, error) {
if join.left.opt.Name == name {
return join.left, nil
}
if join.right.opt.Name == name {
return join.right, nil
}
return nil, types.ErrNotFound
}
//MustGetTable if name not exist, panic
func (join *JoinTable) MustGetTable(name string) *Table {
table, err := join.GetTable(name)
if err != nil {
panic(err)
}
return table
}
//GetData rewrite get data of jointable
func (join *JoinTable) GetData(primaryKey []byte) (*Row, error) {
leftrow, err := join.left.GetData(primaryKey)
if err != nil {
return nil, err
}
rightprimary, err := join.left.index(leftrow, join.Fk)
if err != nil {
return nil, err
}
rightrow, err := join.right.GetData(rightprimary)
if err != nil {
return nil, err
}
rowjoin := join.meta.CreateRow()
rowjoin.Ty = None
rowjoin.Data.(*JoinData).Left = leftrow.Data
rowjoin.Data.(*JoinData).Right = rightrow.Data
return rowjoin, nil
}
//ListIndex 查询jointable 数据
func (join *JoinTable) ListIndex(indexName string, prefix []byte, primaryKey []byte, count, direction int32) (rows []*Row, err error) {
if !strings.Contains(indexName, joinsep) || !join.canGet(indexName) {
return nil, errors.New("joinable query: indexName must be join index")
}
query := &Query{table: join, kvdb: join.left.kvdb.(db.KVDB)}
return query.ListIndex(indexName, prefix, primaryKey, count, direction)
}
//Save 重写默认的save 函数,不仅仅 Save left,right table
//还要save jointable
//没有update 到情况,只有del, add, 性能考虑可以加上 update 的情况
//目前update 是通过 del + add 完成
//left modify: del index, add new index (query right by primary) (check in cache)
//right modify: query all primary in left, include in cache, del index, add new index
//TODO: 没有修改过的数据不需要修改
func (join *JoinTable) Save() (kvs []*types.KeyValue, err error) {
for _, row := range join.left.rows {
if row.Ty == None {
continue
}
err := join.saveLeft(row)
if err != nil {
return nil, err
}
}
for _, row := range join.right.rows {
if row.Ty == None {
continue
}
err := join.saveRight(row)
if err != nil {
return nil, err
}
}
joinkvs, err := join.Table.Save()
if err != nil {
return nil, err
}
kvs = append(kvs, joinkvs...)
leftkvs, err := join.left.Save()
if err != nil {
return nil, err
}
kvs = append(kvs, leftkvs...)
rightkvs, err := join.right.Save()
if err != nil {
return nil, err
}
kvs = append(kvs, rightkvs...)
return deldupKey(kvs), nil
}
func (join *JoinTable) isLeftModify(row *Row) bool {
oldrow := &Row{Data: row.old}
for _, index := range join.leftIndex {
_, _, ismodify, err := join.left.getModify(row, oldrow, index)
if ismodify {
return true
}
if err != nil {
tablelog.Error("isLeftModify", "err", err)
}
}
return false
}
func (join *JoinTable) isRightModify(row *Row) bool {
oldrow := &Row{Data: row.old}
for _, index := range join.rightIndex {
_, _, ismodify, err := join.right.getModify(row, oldrow, index)
if ismodify {
return true
}
if err != nil {
tablelog.Error("isLeftModify", "err", err)
}
}
return false
}
func (join *JoinTable) saveLeft(row *Row) error {
if row.Ty == Update && !join.isLeftModify(row) {
return nil
}
olddata := &JoinData{}
rowjoin := join.meta.CreateRow()
rowjoin.Ty = row.Ty
rowjoin.Primary = row.Primary
rowjoin.Data.(*JoinData).Left = row.Data
olddata.Left = row.old
rightprimary, err := join.left.index(row, join.Fk)
if err != nil {
return err
}
rightrow, incache, err := join.right.findRow(rightprimary)
if err != nil {
return err
}
if incache && rightrow.Ty == Update {
olddata.Right = rightrow.old
} else {
olddata.Right = rightrow.Data
}
//只考虑 left 有变化, 那么就修改(如果right 也修改了,在right中处理)
if row.Ty == Update {
rowjoin.old = olddata
}
rowjoin.Data.(*JoinData).Right = rightrow.Data
join.addRowCache(rowjoin)
return nil
}
func (join *JoinTable) saveRight(row *Row) error {
if row.Ty == Update && !join.isRightModify(row) {
return nil
}
indexName := join.right.opt.Primary
indexValue := row.Primary
q := join.left.GetQuery(join.left.kvdb.(db.KVDB))
rows, err := q.ListIndex(indexName, indexValue, nil, 0, db.ListDESC)
if err != nil && err != types.ErrNotFound {
return err
}
rows, err = join.left.mergeCache(rows, indexName, indexValue)
if err != nil {
return err
}
for _, onerow := range rows {
olddata := &JoinData{Right: row.old, Left: onerow.Data}
if onerow.Ty == Update {
olddata.Left = onerow.old
}
rowjoin := join.meta.CreateRow()
rowjoin.Ty = row.Ty
rowjoin.Primary = onerow.Primary
if row.Ty == Update {
rowjoin.old = olddata
}
rowjoin.Data.(*JoinData).Right = row.Data
rowjoin.Data.(*JoinData).Left = onerow.Data
join.addRowCache(rowjoin)
}
return nil
}
//JoinData 由left 和 right 两个数据组成
type JoinData struct {
Left types.Message
Right types.Message
}
//Reset data
func (msg *JoinData) Reset() {
msg.Left.Reset()
msg.Right.Reset()
}
//ProtoMessage data
func (msg *JoinData) ProtoMessage() {
msg.Left.ProtoMessage()
msg.Right.ProtoMessage()
}
//String string
func (msg *JoinData) String() string {
return msg.Left.String() + msg.Right.String()
}
//JoinMeta left right 合成的一个meta 结构
type JoinMeta struct {
left RowMeta
right RowMeta
data *JoinData
}
//CreateRow create a meta struct
func (tx *JoinMeta) CreateRow() *Row {
return &Row{Data: &JoinData{}}
}
//SetPayload 设置数据
func (tx *JoinMeta) SetPayload(data types.Message) error {
if txdata, ok := data.(*JoinData); ok {
tx.data = txdata
if tx.data.Left != nil && tx.data.Right != nil {
tx.left.SetPayload(tx.data.Left)
tx.right.SetPayload(tx.data.Right)
}
return nil
}
return types.ErrTypeAsset
}
//Get 按照indexName 查询 indexValue
func (tx *JoinMeta) Get(key string) ([]byte, error) {
indexs := strings.Split(key, joinsep)
//获取primary
if len(indexs) <= 1 {
return tx.left.Get(key)
}
var leftvalue []byte
var err error
if indexs[0] != "" {
leftvalue, err = tx.left.Get(indexs[0])
if err != nil {
return nil, err
}
}
rightvalue, err := tx.right.Get(indexs[1])
if err != nil {
return nil, err
}
return JoinKey(leftvalue, rightvalue), nil
}
//JoinKey 两个left 和 right key 合并成一个key
func JoinKey(leftvalue, rightvalue []byte) []byte {
return types.Encode(&types.KeyValue{Key: leftvalue, Value: rightvalue})
}
package table
import (
"fmt"
"testing"
protodata "github.com/33cn/chain33/common/db/table/proto"
"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert"
"github.com/33cn/chain33/types"
)
func TestJoin(t *testing.T) {
dir, leveldb, kvdb := getdb()
defer dbclose(dir, leveldb)
table1, err := NewTable(NewGameRow(), kvdb, optgame)
assert.Nil(t, err)
table2, err := NewTable(NewGameAddrRow(), kvdb, optgameaddr)
assert.Nil(t, err)
tablejoin, err := NewJoinTable(table2, table1, []string{"addr#status", "#status"})
assert.Nil(t, err)
assert.Equal(t, tablejoin.GetLeft(), table2) //table2
assert.Equal(t, tablejoin.GetRight(), table1) //table1
assert.Equal(t, tablejoin.MustGetTable("gameaddr"), table2) //table2
assert.Equal(t, tablejoin.MustGetTable("game"), table1) //table1
rightdata := &protodata.Game{GameID: "gameid1", Status: 1}
tablejoin.MustGetTable("game").Replace(rightdata)
leftdata := &protodata.GameAddr{GameID: "gameid1", Addr: "addr1", Txhash: "hash1"}
tablejoin.MustGetTable("gameaddr").Replace(leftdata)
kvs, err := tablejoin.Save()
assert.Nil(t, err)
assert.Equal(t, 7, len(kvs))
setKV(leveldb, kvs)
//query table
//每个表的查询,用 tablejoin.MustGetTable("gameaddr")
//join query 用 tablejoin.Query
rows, err := tablejoin.ListIndex("addr#status", JoinKey([]byte("addr1"), []byte("1")), nil, 0, 0)
assert.Nil(t, err)
assert.Equal(t, 1, len(rows))
assert.Equal(t, true, proto.Equal(rows[0].Data.(*JoinData).Left, leftdata))
assert.Equal(t, true, proto.Equal(rows[0].Data.(*JoinData).Right, rightdata))
rows, err = tablejoin.ListIndex("#status", JoinKey(nil, []byte("1")), nil, 0, 0)
assert.Nil(t, err)
assert.Equal(t, 1, len(rows))
assert.Equal(t, true, proto.Equal(rows[0].Data.(*JoinData).Left, leftdata))
assert.Equal(t, true, proto.Equal(rows[0].Data.(*JoinData).Right, rightdata))
rightdata = &protodata.Game{GameID: "gameid1", Status: 2}
tablejoin.MustGetTable("game").Replace(rightdata)
kvs, err = tablejoin.Save()
assert.Nil(t, err)
assert.Equal(t, 7, len(kvs))
setKV(leveldb, kvs)
rows, err = tablejoin.ListIndex("addr#status", JoinKey([]byte("addr1"), []byte("2")), nil, 0, 0)
assert.Nil(t, err)
assert.Equal(t, 1, len(rows))
assert.Equal(t, true, proto.Equal(rows[0].Data.(*JoinData).Left, leftdata))
assert.Equal(t, true, proto.Equal(rows[0].Data.(*JoinData).Right, rightdata))
rows, err = tablejoin.ListIndex("#status", JoinKey(nil, []byte("2")), nil, 0, 0)
assert.Nil(t, err)
assert.Equal(t, 1, len(rows))
assert.Equal(t, true, proto.Equal(rows[0].Data.(*JoinData).Left, leftdata))
assert.Equal(t, true, proto.Equal(rows[0].Data.(*JoinData).Right, rightdata))
rightdata = &protodata.Game{GameID: "gameid1", Status: 2}
tablejoin.MustGetTable("game").Replace(rightdata)
kvs, err = tablejoin.Save()
assert.Nil(t, err)
assert.Equal(t, 0, len(kvs))
leftdata = &protodata.GameAddr{GameID: "gameid1", Addr: "addr2", Txhash: "hash1"}
tablejoin.MustGetTable("gameaddr").Replace(leftdata)
kvs, err = tablejoin.Save()
assert.Nil(t, err)
assert.Equal(t, 5, len(kvs))
setKV(leveldb, kvs)
//改回到全部是1的情况
rightdata = &protodata.Game{GameID: "gameid1", Status: 1}
tablejoin.MustGetTable("game").Replace(rightdata)
leftdata = &protodata.GameAddr{GameID: "gameid1", Addr: "addr1", Txhash: "hash1"}
tablejoin.MustGetTable("gameaddr").Replace(leftdata)
kvs, err = tablejoin.Save()
assert.Nil(t, err)
assert.Equal(t, 10, len(kvs))
setKV(leveldb, kvs)
rows, err = tablejoin.ListIndex("addr#status", JoinKey([]byte("addr1"), []byte("1")), nil, 0, 0)
assert.Nil(t, err)
assert.Equal(t, 1, len(rows))
assert.Equal(t, true, proto.Equal(rows[0].Data.(*JoinData).Left, leftdata))
assert.Equal(t, true, proto.Equal(rows[0].Data.(*JoinData).Right, rightdata))
rows, err = tablejoin.ListIndex("#status", JoinKey(nil, []byte("1")), nil, 0, 0)
assert.Nil(t, err)
assert.Equal(t, 1, len(rows))
assert.Equal(t, true, proto.Equal(rows[0].Data.(*JoinData).Left, leftdata))
assert.Equal(t, true, proto.Equal(rows[0].Data.(*JoinData).Right, rightdata))
}
/*
table game
data: Game
index: addr,status,index,type
*/
var optgame = &Option{
Prefix: "LODB",
Name: "game",
Primary: "gameID",
Index: []string{"status"},
}
//GameRow table meta 结构
type GameRow struct {
*protodata.Game
}
//NewGameRow 新建一个meta 结构
func NewGameRow() *GameRow {
return &GameRow{Game: &protodata.Game{}}
}
//CreateRow 新建数据行(注意index 数据一定也要保存到数据中,不能就保存eventid)
func (tx *GameRow) CreateRow() *Row {
return &Row{Data: &protodata.Game{}}
}
//SetPayload 设置数据
func (tx *GameRow) SetPayload(data types.Message) error {
if txdata, ok := data.(*protodata.Game); ok {
tx.Game = txdata
return nil
}
return types.ErrTypeAsset
}
//Get 按照indexName 查询 indexValue
func (tx *GameRow) Get(key string) ([]byte, error) {
if key == "gameID" {
return []byte(tx.GameID), nil
} else if key == "status" {
return []byte(fmt.Sprint(tx.Status)), nil
}
return nil, types.ErrNotFound
}
/*
table struct
data: GameAddr
index: addr,status,index,type
*/
var optgameaddr = &Option{
Prefix: "LODB",
Name: "gameaddr",
Primary: "txhash",
Index: []string{"gameID", "addr"},
}
//GameAddrRow table meta 结构
type GameAddrRow struct {
*protodata.GameAddr
}
//NewGameAddrRow 新建一个meta 结构
func NewGameAddrRow() *GameAddrRow {
return &GameAddrRow{GameAddr: &protodata.GameAddr{}}
}
//CreateRow 新建数据行(注意index 数据一定也要保存到数据中,不能就保存eventid)
func (tx *GameAddrRow) CreateRow() *Row {
return &Row{Data: &protodata.GameAddr{}}
}
//SetPayload 设置数据
func (tx *GameAddrRow) SetPayload(data types.Message) error {
if txdata, ok := data.(*protodata.GameAddr); ok {
tx.GameAddr = txdata
return nil
}
return types.ErrTypeAsset
}
//Get 按照indexName 查询 indexValue
func (tx *GameAddrRow) Get(key string) ([]byte, error) {
if key == "gameID" {
return []byte(tx.GameID), nil
} else if key == "addr" {
return []byte(tx.Addr), nil
} else if key == "txhash" {
return []byte(tx.Txhash), nil
}
return nil, types.ErrNotFound
}
#!/bin/sh
protoc --go_out=plugins=grpc:. ./*.proto --proto_path=.
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: game.proto
package proto
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Game struct {
GameID string `protobuf:"bytes,1,opt,name=gameID,proto3" json:"gameID,omitempty"`
Status int64 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Game) Reset() { *m = Game{} }
func (m *Game) String() string { return proto.CompactTextString(m) }
func (*Game) ProtoMessage() {}
func (*Game) Descriptor() ([]byte, []int) {
return fileDescriptor_game_c30dd93766b91ef0, []int{0}
}
func (m *Game) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Game.Unmarshal(m, b)
}
func (m *Game) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Game.Marshal(b, m, deterministic)
}
func (dst *Game) XXX_Merge(src proto.Message) {
xxx_messageInfo_Game.Merge(dst, src)
}
func (m *Game) XXX_Size() int {
return xxx_messageInfo_Game.Size(m)
}
func (m *Game) XXX_DiscardUnknown() {
xxx_messageInfo_Game.DiscardUnknown(m)
}
var xxx_messageInfo_Game proto.InternalMessageInfo
func (m *Game) GetGameID() string {
if m != nil {
return m.GameID
}
return ""
}
func (m *Game) GetStatus() int64 {
if m != nil {
return m.Status
}
return 0
}
type GameAddr struct {
Txhash string `protobuf:"bytes,1,opt,name=txhash,proto3" json:"txhash,omitempty"`
GameID string `protobuf:"bytes,2,opt,name=gameID,proto3" json:"gameID,omitempty"`
Addr string `protobuf:"bytes,3,opt,name=addr,proto3" json:"addr,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GameAddr) Reset() { *m = GameAddr{} }
func (m *GameAddr) String() string { return proto.CompactTextString(m) }
func (*GameAddr) ProtoMessage() {}
func (*GameAddr) Descriptor() ([]byte, []int) {
return fileDescriptor_game_c30dd93766b91ef0, []int{1}
}
func (m *GameAddr) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GameAddr.Unmarshal(m, b)
}
func (m *GameAddr) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GameAddr.Marshal(b, m, deterministic)
}
func (dst *GameAddr) XXX_Merge(src proto.Message) {
xxx_messageInfo_GameAddr.Merge(dst, src)
}
func (m *GameAddr) XXX_Size() int {
return xxx_messageInfo_GameAddr.Size(m)
}
func (m *GameAddr) XXX_DiscardUnknown() {
xxx_messageInfo_GameAddr.DiscardUnknown(m)
}
var xxx_messageInfo_GameAddr proto.InternalMessageInfo
func (m *GameAddr) GetTxhash() string {
if m != nil {
return m.Txhash
}
return ""
}
func (m *GameAddr) GetGameID() string {
if m != nil {
return m.GameID
}
return ""
}
func (m *GameAddr) GetAddr() string {
if m != nil {
return m.Addr
}
return ""
}
func init() {
proto.RegisterType((*Game)(nil), "proto.Game")
proto.RegisterType((*GameAddr)(nil), "proto.GameAddr")
}
func init() { proto.RegisterFile("game.proto", fileDescriptor_game_c30dd93766b91ef0) }
var fileDescriptor_game_c30dd93766b91ef0 = []byte{
// 131 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4a, 0x4f, 0xcc, 0x4d,
0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x53, 0x4a, 0x66, 0x5c, 0x2c, 0xee, 0x89,
0xb9, 0xa9, 0x42, 0x62, 0x5c, 0x6c, 0x20, 0x49, 0x4f, 0x17, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce,
0x20, 0x28, 0x0f, 0x24, 0x5e, 0x5c, 0x92, 0x58, 0x52, 0x5a, 0x2c, 0xc1, 0xa4, 0xc0, 0xa8, 0xc1,
0x1c, 0x04, 0xe5, 0x29, 0xf9, 0x71, 0x71, 0x80, 0xf4, 0x39, 0xa6, 0xa4, 0x14, 0x81, 0xd4, 0x94,
0x54, 0x64, 0x24, 0x16, 0x67, 0xc0, 0xf4, 0x42, 0x78, 0x48, 0x66, 0x32, 0xa1, 0x98, 0x29, 0xc4,
0xc5, 0x92, 0x98, 0x92, 0x52, 0x24, 0xc1, 0x0c, 0x16, 0x05, 0xb3, 0x9d, 0xd8, 0xa3, 0x20, 0x0e,
0x4a, 0x62, 0x03, 0x53, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd5, 0x93, 0x12, 0xbb, 0xac,
0x00, 0x00, 0x00,
}
syntax = "proto3";
package proto;
option go_package = "proto";
message Game {
string gameID = 1;
int64 status = 2;
}
message GameAddr {
string txhash = 1;
string gameID = 2;
string addr = 3;
}
\ No newline at end of file
...@@ -9,12 +9,53 @@ import ( ...@@ -9,12 +9,53 @@ import (
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
) )
type tabler interface {
getMeta() RowMeta
getOpt() *Option
indexPrefix(string) []byte
GetData([]byte) (*Row, error)
index(*Row, string) ([]byte, error)
getIndexKey(string, []byte, []byte) []byte
primaryPrefix() []byte
getRow(value []byte) (*Row, error)
}
//Query 列表查询结构 //Query 列表查询结构
type Query struct { type Query struct {
table *Table table tabler
kvdb db.KVDB kvdb db.KVDB
} }
//List 通过某个数据,查询
func (query *Query) List(indexName string, data types.Message, primaryKey []byte, count, direction int32) (rows []*Row, err error) {
var prefix []byte
if data != nil {
query.table.getMeta().SetPayload(data)
querykey := indexName
if isPrimaryIndex(indexName) {
querykey = query.table.getOpt().Primary
}
prefix, err = query.table.getMeta().Get(querykey)
if err != nil {
return nil, err
}
}
return query.ListIndex(indexName, prefix, primaryKey, count, direction)
}
//ListOne 通过某个数据,查询一行
func (query *Query) ListOne(indexName string, data types.Message, primaryKey []byte) (row *Row, err error) {
rows, err := query.List(indexName, data, primaryKey, 1, db.ListDESC)
if err != nil {
return nil, err
}
return rows[0], nil
}
func isPrimaryIndex(indexName string) bool {
return indexName == "" || indexName == "auto" || indexName == "primary"
}
//ListIndex 根据索引查询列表 //ListIndex 根据索引查询列表
//index 用哪个index //index 用哪个index
//prefix 必须要符合的前缀, 可以为空 //prefix 必须要符合的前缀, 可以为空
...@@ -22,8 +63,8 @@ type Query struct { ...@@ -22,8 +63,8 @@ type Query struct {
//count 最多取的数量 //count 最多取的数量
//direction 方向 //direction 方向
func (query *Query) ListIndex(indexName string, prefix []byte, primaryKey []byte, count, direction int32) (rows []*Row, err error) { func (query *Query) ListIndex(indexName string, prefix []byte, primaryKey []byte, count, direction int32) (rows []*Row, err error) {
if indexName == "" { if isPrimaryIndex(indexName) || indexName == query.table.getOpt().Primary {
return query.ListPrimary(prefix, primaryKey, count, direction) return query.listPrimary(prefix, primaryKey, count, direction)
} }
p := query.table.indexPrefix(indexName) p := query.table.indexPrefix(indexName)
var k []byte var k []byte
...@@ -60,11 +101,14 @@ func (query *Query) ListIndex(indexName string, prefix []byte, primaryKey []byte ...@@ -60,11 +101,14 @@ func (query *Query) ListIndex(indexName string, prefix []byte, primaryKey []byte
} }
rows = append(rows, row) rows = append(rows, row)
} }
if len(rows) == 0 {
return nil, types.ErrNotFound
}
return rows, nil return rows, nil
} }
//ListPrimary list primary data //ListPrimary list primary data
func (query *Query) ListPrimary(prefix []byte, primaryKey []byte, count, direction int32) (rows []*Row, err error) { func (query *Query) listPrimary(prefix []byte, primaryKey []byte, count, direction int32) (rows []*Row, err error) {
p := query.table.primaryPrefix() p := query.table.primaryPrefix()
var k []byte var k []byte
if primaryKey != nil { if primaryKey != nil {
...@@ -90,6 +134,9 @@ func (query *Query) ListPrimary(prefix []byte, primaryKey []byte, count, directi ...@@ -90,6 +134,9 @@ func (query *Query) ListPrimary(prefix []byte, primaryKey []byte, count, directi
} }
rows = append(rows, row) rows = append(rows, row)
} }
if len(rows) == 0 {
return nil, types.ErrNotFound
}
return rows, nil return rows, nil
} }
......
...@@ -8,11 +8,13 @@ package table ...@@ -8,11 +8,13 @@ package table
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"strings" "strings"
"github.com/33cn/chain33/common/db" "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
"github.com/golang/protobuf/proto"
) )
//设计结构: //设计结构:
...@@ -36,17 +38,19 @@ del: ...@@ -36,17 +38,19 @@ del:
利用 primaryKey + index 删除所有的 数据 和 索引 利用 primaryKey + index 删除所有的 数据 和 索引
*/ */
//表关联设计
//指出是 添加 还是 删除 行 //指出是 添加 还是 删除 行
//primary key auto 的del 需要指定 primary key //primary key auto 的del 需要指定 primary key
const ( const (
None = iota None = iota
Add Add
Update
Del Del
) )
//meta key //meta key
const meta = "#m#" const meta = sep + "m" + sep
const data = "#d#" const data = sep + "d" + sep
//RowMeta 定义行的操作 //RowMeta 定义行的操作
type RowMeta interface { type RowMeta interface {
...@@ -60,6 +64,7 @@ type Row struct { ...@@ -60,6 +64,7 @@ type Row struct {
Ty int Ty int
Primary []byte Primary []byte
Data types.Message Data types.Message
old types.Message
} }
func encodeInt64(p int64) ([]byte, error) { func encodeInt64(p int64) ([]byte, error) {
...@@ -124,9 +129,13 @@ type Option struct { ...@@ -124,9 +129,13 @@ type Option struct {
Prefix string Prefix string
Name string Name string
Primary string Primary string
Join bool
Index []string Index []string
} }
const sep = "-"
const joinsep = "#"
//NewTable 新建一个表格 //NewTable 新建一个表格
//primary 可以为: auto, 由系统自动创建 //primary 可以为: auto, 由系统自动创建
//index 可以为nil //index 可以为nil
...@@ -135,7 +144,10 @@ func NewTable(rowmeta RowMeta, kvdb db.KV, opt *Option) (*Table, error) { ...@@ -135,7 +144,10 @@ func NewTable(rowmeta RowMeta, kvdb db.KV, opt *Option) (*Table, error) {
return nil, ErrTooManyIndex return nil, ErrTooManyIndex
} }
for _, index := range opt.Index { for _, index := range opt.Index {
if strings.Contains(index, "#") { if strings.Contains(index, sep) || index == "primary" {
return nil, ErrIndexKey
}
if !opt.Join && strings.Contains(index, joinsep) {
return nil, ErrIndexKey return nil, ErrIndexKey
} }
} }
...@@ -145,13 +157,17 @@ func NewTable(rowmeta RowMeta, kvdb db.KV, opt *Option) (*Table, error) { ...@@ -145,13 +157,17 @@ func NewTable(rowmeta RowMeta, kvdb db.KV, opt *Option) (*Table, error) {
if _, err := getPrimaryKey(rowmeta, opt.Primary); err != nil { if _, err := getPrimaryKey(rowmeta, opt.Primary); err != nil {
return nil, err return nil, err
} }
//不允许有# //不允许有 "-"
if strings.Contains(opt.Prefix, "#") || strings.Contains(opt.Name, "#") { if strings.Contains(opt.Prefix, sep) || strings.Contains(opt.Name, sep) {
return nil, ErrTablePrefixOrTableName return nil, ErrTablePrefixOrTableName
} }
dataprefix := opt.Prefix + "#" + opt.Name + data //非jointable 不允许 "#"
metaprefix := opt.Prefix + "#" + opt.Name + meta if !opt.Join && strings.Contains(opt.Name, joinsep) {
count := NewCount(opt.Prefix, opt.Name+"#autoinc#", kvdb) return nil, ErrTablePrefixOrTableName
}
dataprefix := opt.Prefix + sep + opt.Name + data
metaprefix := opt.Prefix + sep + opt.Name + meta
count := NewCount(opt.Prefix, opt.Name+sep+"autoinc"+sep, kvdb)
return &Table{ return &Table{
meta: rowmeta, meta: rowmeta,
kvdb: kvdb, kvdb: kvdb,
...@@ -166,7 +182,7 @@ func getPrimaryKey(meta RowMeta, primary string) ([]byte, error) { ...@@ -166,7 +182,7 @@ func getPrimaryKey(meta RowMeta, primary string) ([]byte, error) {
if primary == "" { if primary == "" {
return nil, ErrEmptyPrimaryKey return nil, ErrEmptyPrimaryKey
} }
if strings.Contains(primary, "#") { if strings.Contains(primary, sep) {
return nil, ErrPrimaryKey return nil, ErrPrimaryKey
} }
if primary != "auto" { if primary != "auto" {
...@@ -177,15 +193,70 @@ func getPrimaryKey(meta RowMeta, primary string) ([]byte, error) { ...@@ -177,15 +193,70 @@ func getPrimaryKey(meta RowMeta, primary string) ([]byte, error) {
} }
func (table *Table) addRowCache(row *Row) { func (table *Table) addRowCache(row *Row) {
table.rowmap[string(row.Primary)] = row primary := string(row.Primary)
if row.Ty == Del {
delete(table.rowmap, primary)
} else if row.Ty == Add || row.Ty == Update {
table.rowmap[primary] = row
}
table.rows = append(table.rows, row) table.rows = append(table.rows, row)
} }
func (table *Table) findRow(primary []byte) (*Row, error) { func (table *Table) delRowCache(row *Row) {
row.Ty = None
primary := string(row.Primary)
delete(table.rowmap, primary)
}
func (table *Table) mergeCache(rows []*Row, indexName string, indexValue []byte) ([]*Row, error) {
replaced := make(map[string]bool)
for i, row := range rows {
if cacherow, ok := table.rowmap[string(row.Primary)]; ok {
rows[i] = cacherow
replaced[string(row.Primary)] = true
}
}
//add not in db but in cache rows
for _, row := range table.rowmap {
if _, ok := replaced[string(row.Primary)]; ok {
continue
}
v, err := table.index(row, indexName)
if err != nil {
return nil, err
}
if bytes.Equal(v, indexValue) {
rows = append(rows, row)
}
}
return rows, nil
}
func (table *Table) findRow(primary []byte) (*Row, bool, error) {
if row, ok := table.rowmap[string(primary)]; ok { if row, ok := table.rowmap[string(primary)]; ok {
return row, nil return row, true, nil
}
row, err := table.GetData(primary)
return row, false, err
}
func (table *Table) hasIndex(name string) bool {
for _, index := range table.opt.Index {
if index == name {
return true
}
} }
return table.GetData(primary) return false
}
func (table *Table) canGet(name string) bool {
row := table.meta.CreateRow()
err := table.meta.SetPayload(row.Data)
if err != nil {
return false
}
_, err = table.meta.Get(name)
return err == nil
} }
func (table *Table) checkIndex(data types.Message) error { func (table *Table) checkIndex(data types.Message) error {
...@@ -255,17 +326,19 @@ func (table *Table) Replace(data types.Message) error { ...@@ -255,17 +326,19 @@ func (table *Table) Replace(data types.Message) error {
return nil return nil
} }
//如果没有找到行, 那么添加 //如果没有找到行, 那么添加
row, err := table.findRow(primaryKey) //TODO: 优化保存策略,不需要修改没有变化的index
row, incache, err := table.findRow(primaryKey)
if err == types.ErrNotFound { if err == types.ErrNotFound {
table.addRowCache(&Row{Data: data, Primary: primaryKey, Ty: Add}) table.addRowCache(&Row{Data: data, Primary: primaryKey, Ty: Add})
return nil return nil
} }
//update or add
if incache {
row.Data = data
return nil
}
//更新数据 //更新数据
delrow := *row table.addRowCache(&Row{Data: data, Primary: primaryKey, Ty: Update, old: row.Data})
delrow.Ty = Del
//update 是一个del 和 update 的组合
table.addRowCache(&delrow)
table.addRowCache(&Row{Data: data, Primary: primaryKey, Ty: Add})
return nil return nil
} }
...@@ -279,7 +352,7 @@ func (table *Table) Add(data types.Message) error { ...@@ -279,7 +352,7 @@ func (table *Table) Add(data types.Message) error {
return err return err
} }
//find in cache + db //find in cache + db
_, err = table.findRow(primaryKey) _, _, err = table.findRow(primaryKey)
if err != types.ErrNotFound { if err != types.ErrNotFound {
return ErrDupPrimaryKey return ErrDupPrimaryKey
} }
...@@ -300,25 +373,33 @@ func (table *Table) Update(primaryKey []byte, newdata types.Message) (err error) ...@@ -300,25 +373,33 @@ func (table *Table) Update(primaryKey []byte, newdata types.Message) (err error)
if !bytes.Equal(p1, primaryKey) { if !bytes.Equal(p1, primaryKey) {
return types.ErrInvalidParam return types.ErrInvalidParam
} }
row, err := table.findRow(primaryKey) row, incache, err := table.findRow(primaryKey)
//查询发生错误 //查询发生错误
if err != nil { if err != nil {
return err return err
} }
delrow := *row //update and add
delrow.Ty = Del if incache {
//update 是一个del 和 update 的组合 row.Data = newdata
table.addRowCache(&delrow) return nil
table.addRowCache(&Row{Data: newdata, Primary: primaryKey, Ty: Add}) }
table.addRowCache(&Row{Data: newdata, Primary: primaryKey, Ty: Update, old: row.Data})
return nil return nil
} }
//Del 在表格中删除一行(包括删除索引) //Del 在表格中删除一行(包括删除索引)
func (table *Table) Del(primaryKey []byte) error { func (table *Table) Del(primaryKey []byte) error {
row, err := table.findRow(primaryKey) row, incache, err := table.findRow(primaryKey)
if err != nil { if err != nil {
return err return err
} }
if incache {
table.delRowCache(row)
if row.Ty == Add {
return nil
}
}
//copy row
delrow := *row delrow := *row
delrow.Ty = Del delrow.Ty = Del
table.addRowCache(&delrow) table.addRowCache(&delrow)
...@@ -334,7 +415,7 @@ func (table *Table) getDataKey(primaryKey []byte) []byte { ...@@ -334,7 +415,7 @@ func (table *Table) getDataKey(primaryKey []byte) []byte {
func (table *Table) getIndexKey(indexName string, index, primaryKey []byte) []byte { func (table *Table) getIndexKey(indexName string, index, primaryKey []byte) []byte {
key := table.indexPrefix(indexName) key := table.indexPrefix(indexName)
key = append(key, index...) key = append(key, index...)
key = append(key, []byte("#")...) key = append(key, []byte(sep)...)
key = append(key, primaryKey...) key = append(key, primaryKey...)
return key return key
} }
...@@ -344,7 +425,7 @@ func (table *Table) primaryPrefix() []byte { ...@@ -344,7 +425,7 @@ func (table *Table) primaryPrefix() []byte {
} }
func (table *Table) indexPrefix(indexName string) []byte { func (table *Table) indexPrefix(indexName string) []byte {
key := append([]byte(table.metaprefix), []byte(indexName+"#")...) key := append([]byte(table.metaprefix), []byte(indexName+sep)...)
return key return key
} }
...@@ -405,7 +486,31 @@ func (table *Table) Save() (kvs []*types.KeyValue, err error) { ...@@ -405,7 +486,31 @@ func (table *Table) Save() (kvs []*types.KeyValue, err error) {
//del cache //del cache
table.rowmap = make(map[string]*Row) table.rowmap = make(map[string]*Row)
table.rows = nil table.rows = nil
return kvs, nil return deldupKey(kvs), nil
}
func deldupKey(kvs []*types.KeyValue) []*types.KeyValue {
dupindex := make(map[string]int)
hasdup := false
for i, kv := range kvs {
if _, ok := dupindex[string(kv.Key)]; ok {
hasdup = true
}
dupindex[string(kv.Key)] = i
}
//没有重复的情况下,不需要重新处理
if !hasdup {
return kvs
}
index := 0
for i, kv := range kvs {
lastindex := dupindex[string(kv.Key)]
if i == lastindex {
kvs[index] = kv
index++
}
}
return kvs[0:index]
} }
func pad(i int64) string { func pad(i int64) string {
...@@ -415,13 +520,21 @@ func pad(i int64) string { ...@@ -415,13 +520,21 @@ func pad(i int64) string {
func (table *Table) saveRow(row *Row) (kvs []*types.KeyValue, err error) { func (table *Table) saveRow(row *Row) (kvs []*types.KeyValue, err error) {
if row.Ty == Del { if row.Ty == Del {
return table.delRow(row) return table.delRow(row)
} else if row.Ty == Add {
return table.addRow(row)
} else if row.Ty == Update {
return table.updateRow(row)
} else if row.Ty == None {
return nil, nil
} }
return table.addRow(row) return nil, errors.New("save table unknow action")
} }
func (table *Table) delRow(row *Row) (kvs []*types.KeyValue, err error) { func (table *Table) delRow(row *Row) (kvs []*types.KeyValue, err error) {
deldata := &types.KeyValue{Key: table.getDataKey(row.Primary)} if !table.opt.Join {
kvs = append(kvs, deldata) deldata := &types.KeyValue{Key: table.getDataKey(row.Primary)}
kvs = append(kvs, deldata)
}
for _, index := range table.opt.Index { for _, index := range table.opt.Index {
indexkey, err := table.index(row, index) indexkey, err := table.index(row, index)
if err != nil { if err != nil {
...@@ -434,12 +547,14 @@ func (table *Table) delRow(row *Row) (kvs []*types.KeyValue, err error) { ...@@ -434,12 +547,14 @@ func (table *Table) delRow(row *Row) (kvs []*types.KeyValue, err error) {
} }
func (table *Table) addRow(row *Row) (kvs []*types.KeyValue, err error) { func (table *Table) addRow(row *Row) (kvs []*types.KeyValue, err error) {
data, err := row.Encode() if !table.opt.Join {
if err != nil { data, err := row.Encode()
return nil, err if err != nil {
return nil, err
}
adddata := &types.KeyValue{Key: table.getDataKey(row.Primary), Value: data}
kvs = append(kvs, adddata)
} }
adddata := &types.KeyValue{Key: table.getDataKey(row.Primary), Value: data}
kvs = append(kvs, adddata)
for _, index := range table.opt.Index { for _, index := range table.opt.Index {
indexkey, err := table.index(row, index) indexkey, err := table.index(row, index)
if err != nil { if err != nil {
...@@ -451,7 +566,64 @@ func (table *Table) addRow(row *Row) (kvs []*types.KeyValue, err error) { ...@@ -451,7 +566,64 @@ func (table *Table) addRow(row *Row) (kvs []*types.KeyValue, err error) {
return kvs, nil return kvs, nil
} }
func (table *Table) updateRow(row *Row) (kvs []*types.KeyValue, err error) {
if proto.Equal(row.Data, row.old) {
return nil, nil
}
if !table.opt.Join {
data, err := row.Encode()
if err != nil {
return nil, err
}
adddata := &types.KeyValue{Key: table.getDataKey(row.Primary), Value: data}
kvs = append(kvs, adddata)
}
oldrow := &Row{Data: row.old}
for _, index := range table.opt.Index {
indexkey, oldkey, ismodify, err := table.getModify(row, oldrow, index)
if err != nil {
return nil, err
}
if !ismodify {
continue
}
//del old
delindex := &types.KeyValue{Key: table.getIndexKey(index, oldkey, row.Primary)}
kvs = append(kvs, delindex)
//add new
addindex := &types.KeyValue{Key: table.getIndexKey(index, indexkey, row.Primary), Value: row.Primary}
kvs = append(kvs, addindex)
}
return kvs, nil
}
func (table *Table) getModify(row, oldrow *Row, index string) ([]byte, []byte, bool, error) {
if oldrow.Data == nil {
return nil, nil, false, ErrNilValue
}
indexkey, err := table.index(row, index)
if err != nil {
return nil, nil, false, err
}
oldkey, err := table.index(oldrow, index)
if err != nil {
return nil, nil, false, err
}
if bytes.Equal(indexkey, oldkey) {
return indexkey, oldkey, false, nil
}
return indexkey, oldkey, true, nil
}
//GetQuery 获取查询结构 //GetQuery 获取查询结构
func (table *Table) GetQuery(kvdb db.KVDB) *Query { func (table *Table) GetQuery(kvdb db.KVDB) *Query {
return &Query{table: table, kvdb: kvdb} return &Query{table: table, kvdb: kvdb}
} }
func (table *Table) getMeta() RowMeta {
return table.meta
}
func (table *Table) getOpt() *Option {
return table.opt
}
...@@ -115,20 +115,43 @@ func TestTransactinList(t *testing.T) { ...@@ -115,20 +115,43 @@ func TestTransactinList(t *testing.T) {
} else { } else {
assert.Equal(t, true, proto.Equal(tx3, rows[0].Data)) assert.Equal(t, true, proto.Equal(tx3, rows[0].Data))
} }
//List data
rows, err = query.List("From", tx3, primary, 0, 0)
assert.Nil(t, err)
assert.Equal(t, 1, len(rows))
if bytes.Compare(tx3.Hash(), tx4.Hash()) > 0 {
assert.Equal(t, true, proto.Equal(tx4, rows[0].Data))
} else {
assert.Equal(t, true, proto.Equal(tx3, rows[0].Data))
}
rows, err = query.ListIndex("From", []byte(addr1[0:10]), primary, 0, 0) rows, err = query.ListIndex("From", []byte(addr1[0:10]), primary, 0, 0)
assert.Equal(t, types.ErrNotFound, err) assert.Equal(t, types.ErrNotFound, err)
assert.Equal(t, 0, len(rows)) assert.Equal(t, 0, len(rows))
//ListPrimary all //ListPrimary all
rows, err = query.ListPrimary(nil, nil, 0, 0) rows, err = query.ListIndex("primary", nil, nil, 0, 0)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 4, len(rows)) assert.Equal(t, 4, len(rows))
//ListPrimary all
rows, err = query.List("primary", nil, nil, 0, 0)
assert.Nil(t, err)
assert.Equal(t, 4, len(rows))
row, err := query.ListOne("primary", nil, nil)
assert.Nil(t, err)
assert.Equal(t, row, rows[0])
primary = rows[0].Primary primary = rows[0].Primary
rows, err = query.ListPrimary(primary[0:10], nil, 0, 0) rows, err = query.ListIndex("auto", primary, nil, 0, 0)
assert.Nil(t, err)
assert.Equal(t, 1, len(rows))
rows, err = query.List("", rows[0].Data, nil, 0, 0)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(rows)) assert.Equal(t, 1, len(rows))
rows, err = query.ListPrimary(nil, primary, 0, 0) rows, err = query.ListIndex("", nil, primary, 0, 0)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 3, len(rows)) assert.Equal(t, 3, len(rows))
} }
...@@ -207,16 +230,16 @@ func TestTransactinListAuto(t *testing.T) { ...@@ -207,16 +230,16 @@ func TestTransactinListAuto(t *testing.T) {
assert.Equal(t, types.ErrNotFound, err) assert.Equal(t, types.ErrNotFound, err)
assert.Equal(t, 0, len(rows)) assert.Equal(t, 0, len(rows))
//ListPrimary all //ListPrimary all
rows, err = query.ListPrimary(nil, nil, 0, db.ListASC) rows, err = query.ListIndex("", nil, nil, 0, db.ListASC)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 4, len(rows)) assert.Equal(t, 4, len(rows))
primary = rows[0].Primary primary = rows[0].Primary
rows, err = query.ListPrimary(primary, nil, 0, db.ListASC) rows, err = query.ListIndex("", primary, nil, 0, db.ListASC)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(rows)) assert.Equal(t, 1, len(rows))
rows, err = query.ListPrimary(nil, primary, 0, db.ListASC) rows, err = query.ListIndex("", nil, primary, 0, db.ListASC)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 3, len(rows)) assert.Equal(t, 3, len(rows))
} }
...@@ -235,6 +258,7 @@ func mergeDup(kvs []*types.KeyValue) (kvset []*types.KeyValue) { ...@@ -235,6 +258,7 @@ func mergeDup(kvs []*types.KeyValue) (kvset []*types.KeyValue) {
} }
func setKV(kvdb db.DB, kvs []*types.KeyValue) { func setKV(kvdb db.DB, kvs []*types.KeyValue) {
//printKV(kvs)
batch := kvdb.NewBatch(true) batch := kvdb.NewBatch(true)
for i := 0; i < len(kvs); i++ { for i := 0; i < len(kvs); i++ {
if kvs[i].Value == nil { if kvs[i].Value == nil {
...@@ -251,7 +275,7 @@ func setKV(kvdb db.DB, kvs []*types.KeyValue) { ...@@ -251,7 +275,7 @@ func setKV(kvdb db.DB, kvs []*types.KeyValue) {
func printKV(kvs []*types.KeyValue) { func printKV(kvs []*types.KeyValue) {
for i := 0; i < len(kvs); i++ { for i := 0; i < len(kvs); i++ {
fmt.Println("KV", i, string(kvs[i].Key), common.ToHex(kvs[i].Value)) fmt.Printf("KV %d %s(%s)\n", i, string(kvs[i].Key), common.ToHex(kvs[i].Value))
} }
} }
...@@ -301,7 +325,7 @@ func TestDel(t *testing.T) { ...@@ -301,7 +325,7 @@ func TestDel(t *testing.T) {
//save 然后从列表中读取 //save 然后从列表中读取
kvs, err := table.Save() kvs, err := table.Save()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, len(kvs), 9) assert.Equal(t, len(kvs), 6)
//save to database //save to database
setKV(leveldb, kvs) setKV(leveldb, kvs)
//printKV(kvs) //printKV(kvs)
...@@ -343,7 +367,7 @@ func TestUpdate(t *testing.T) { ...@@ -343,7 +367,7 @@ func TestUpdate(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
kvs, err := table.Save() kvs, err := table.Save()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, len(kvs), 9) assert.Equal(t, len(kvs), 3)
//save to database //save to database
setKV(leveldb, kvs) setKV(leveldb, kvs)
query := table.GetQuery(kvdb) query := table.GetQuery(kvdb)
...@@ -372,22 +396,23 @@ func TestReplace(t *testing.T) { ...@@ -372,22 +396,23 @@ func TestReplace(t *testing.T) {
assert.Equal(t, err, ErrDupPrimaryKey) assert.Equal(t, err, ErrDupPrimaryKey)
//不改变hash,改变签名 //不改变hash,改变签名
tx1.Signature = nil tx2 := *tx1
err = table.Replace(tx1) tx2.Signature = nil
err = table.Replace(&tx2)
assert.Nil(t, err) assert.Nil(t, err)
//save 然后从列表中读取 //save 然后从列表中读取
kvs, err := table.Save() kvs, err := table.Save()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, len(kvs), 9) assert.Equal(t, 3, len(kvs))
//save to database //save to database
setKV(leveldb, kvs) setKV(leveldb, kvs)
query := table.GetQuery(kvdb) query := table.GetQuery(kvdb)
_, err = query.ListIndex("From", []byte(addr1[0:10]), nil, 0, 0) _, err = query.ListIndex("From", []byte(addr1[0:10]), nil, 0, 0)
assert.Equal(t, err, types.ErrNotFound) assert.Equal(t, err, types.ErrNotFound)
rows, err := query.ListIndex("From", []byte(tx1.From()), nil, 0, 0) rows, err := query.ListIndex("From", []byte(tx2.From()), nil, 0, 0)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, rows[0].Data.(*types.Transaction).From(), tx1.From()) assert.Equal(t, rows[0].Data.(*types.Transaction).From(), tx2.From())
} }
type TransactionRow struct { type TransactionRow struct {
......
...@@ -7,6 +7,8 @@ package executor ...@@ -7,6 +7,8 @@ package executor
import ( import (
"bytes" "bytes"
"github.com/pkg/errors"
drivers "github.com/33cn/chain33/system/dapp" drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
) )
...@@ -61,37 +63,46 @@ func isAllowKeyWrite(key, realExecer []byte, tx *types.Transaction, height int64 ...@@ -61,37 +63,46 @@ func isAllowKeyWrite(key, realExecer []byte, tx *types.Transaction, height int64
} }
func isAllowLocalKey(execer []byte, key []byte) error { func isAllowLocalKey(execer []byte, key []byte) error {
if err := isAllowLocalKey2(execer, key); err != nil { err := isAllowLocalKey2(execer, key)
if err != nil {
realexec := types.GetRealExecName(execer) realexec := types.GetRealExecName(execer)
if bytes.Equal(realexec, execer) { if !bytes.Equal(realexec, execer) {
return err err2 := isAllowLocalKey2(realexec, key)
err = errors.Wrapf(err2, "1st check err: %s. 2nd check err", err.Error())
} }
return isAllowLocalKey2(realexec, key) if err != nil {
elog.Error("isAllowLocalKey failed", "err", err.Error())
return errors.Cause(err)
}
} }
return nil return nil
} }
func isAllowLocalKey2(execer []byte, key []byte) error { func isAllowLocalKey2(execer []byte, key []byte) error {
if len(execer) < 1 { if len(execer) < 1 {
return types.ErrLocalPrefix return errors.Wrap(types.ErrLocalPrefix, "execer empty")
} }
minkeylen := len(types.LocalPrefix) + len(execer) + 2 minkeylen := len(types.LocalPrefix) + len(execer) + 2
if len(key) <= minkeylen { if len(key) <= minkeylen {
elog.Error("isAllowLocalKey too short", "key", string(key), "exec", string(execer)) err := errors.Wrapf(types.ErrLocalKeyLen, "isAllowLocalKey too short. key=%s exec=%s", string(key), string(execer))
return types.ErrLocalKeyLen return err
} }
if key[minkeylen-1] != '-' { if key[minkeylen-1] != '-' {
elog.Error("isAllowLocalKey prefix last char is not '-'", "key", string(key), "exec", string(execer), err := errors.Wrapf(types.ErrLocalPrefix,
"minkeylen", minkeylen) "isAllowLocalKey prefix last char is not '-'. key=%s exec=%s minkeylen=%d title=%s",
return types.ErrLocalPrefix string(key), string(execer), minkeylen, types.GetTitle())
return err
} }
if !bytes.HasPrefix(key, types.LocalPrefix) { if !bytes.HasPrefix(key, types.LocalPrefix) {
elog.Error("isAllowLocalKey common prefix not match", "key", string(key), "exec", string(execer)) err := errors.Wrapf(types.ErrLocalPrefix, "isAllowLocalKey common prefix not match. key=%s exec=%s",
return types.ErrLocalPrefix string(key), string(execer))
return err
} }
if !bytes.HasPrefix(key[len(types.LocalPrefix)+1:], execer) { if !bytes.HasPrefix(key[len(types.LocalPrefix)+1:], execer) {
elog.Error("isAllowLocalKey key prefix not match", "key", string(key), "exec", string(execer)) err := errors.Wrapf(types.ErrLocalPrefix, "isAllowLocalKey key prefix not match. key=%s exec=%s",
return types.ErrLocalPrefix string(key), string(execer))
return err
} }
return nil return nil
} }
...@@ -134,6 +134,8 @@ func TestKeyLocalAllow(t *testing.T) { ...@@ -134,6 +134,8 @@ func TestKeyLocalAllow(t *testing.T) {
assert.Equal(t, err, types.ErrLocalPrefix) assert.Equal(t, err, types.ErrLocalPrefix)
err = isAllowLocalKey([]byte("user.p.para.paracross"), []byte("LODB-user.p.para.paracross-xxxx")) err = isAllowLocalKey([]byte("user.p.para.paracross"), []byte("LODB-user.p.para.paracross-xxxx"))
assert.Nil(t, err) assert.Nil(t, err)
err = isAllowLocalKey([]byte("user.p.para.user.wasm.abc"), []byte("LODB-user.p.para.user.wasm.abc-xxxx"))
assert.Nil(t, err)
err = isAllowLocalKey([]byte("user.p.para.paracross"), []byte("LODB-paracross-xxxx")) err = isAllowLocalKey([]byte("user.p.para.paracross"), []byte("LODB-paracross-xxxx"))
assert.Nil(t, err) assert.Nil(t, err)
} }
...@@ -53,6 +53,36 @@ func (c *channelClient) CreateRawTransaction(param *types.CreateTx) ([]byte, err ...@@ -53,6 +53,36 @@ func (c *channelClient) CreateRawTransaction(param *types.CreateTx) ([]byte, err
return types.CallCreateTx(execer, "", param) return types.CallCreateTx(execer, "", param)
} }
func (c *channelClient) ReWriteRawTx(param *types.ReWriteRawTx) ([]byte, error) {
if param == nil || param.Tx == "" {
log.Error("ReWriteRawTx", "Error", types.ErrInvalidParam)
return nil, types.ErrInvalidParam
}
tx, err := decodeTx(param.Tx)
if err != nil {
return nil, err
}
if param.Execer != nil {
tx.Execer = param.Execer
}
if param.To != "" {
tx.To = param.To
}
if param.Fee != 0 {
tx.Fee = param.Fee
}
if param.Expire != "" {
expire, err := types.ParseExpire(param.Expire)
if err != nil {
return nil, err
}
tx.Expire = expire
}
return types.FormatTxEncode(string(tx.Execer), tx)
}
// CreateRawTxGroup create rawtransaction for group // CreateRawTxGroup create rawtransaction for group
func (c *channelClient) CreateRawTxGroup(param *types.CreateTransactionGroup) ([]byte, error) { func (c *channelClient) CreateRawTxGroup(param *types.CreateTransactionGroup) ([]byte, error) {
if param == nil || len(param.Txs) <= 1 { if param == nil || len(param.Txs) <= 1 {
......
...@@ -36,6 +36,15 @@ func (g *Grpc) CreateRawTransaction(ctx context.Context, in *pb.CreateTx) (*pb.U ...@@ -36,6 +36,15 @@ func (g *Grpc) CreateRawTransaction(ctx context.Context, in *pb.CreateTx) (*pb.U
return &pb.UnsignTx{Data: reply}, nil return &pb.UnsignTx{Data: reply}, nil
} }
// ReWriteRawTx re-write raw tx parameters of grpc
func (g *Grpc) ReWriteRawTx(ctx context.Context, in *pb.ReWriteRawTx) (*pb.UnsignTx, error) {
reply, err := g.cli.ReWriteRawTx(in)
if err != nil {
return nil, err
}
return &pb.UnsignTx{Data: reply}, nil
}
// CreateTransaction create transaction of grpc // CreateTransaction create transaction of grpc
func (g *Grpc) CreateTransaction(ctx context.Context, in *pb.CreateTxIn) (*pb.UnsignTx, error) { func (g *Grpc) CreateTransaction(ctx context.Context, in *pb.CreateTxIn) (*pb.UnsignTx, error) {
execer := pb.ExecName(string(in.Execer)) execer := pb.ExecName(string(in.Execer))
......
...@@ -1046,3 +1046,28 @@ func TestQueryTransaction(t *testing.T) { ...@@ -1046,3 +1046,28 @@ func TestQueryTransaction(t *testing.T) {
//func Test_CreateTxGroup(t *testing.T) { //func Test_CreateTxGroup(t *testing.T) {
// testCreateTxGroupOk(t) // testCreateTxGroupOk(t)
//} //}
func TestReWriteRawTx(t *testing.T) {
txHex1 := "0a05636f696e73122c18010a281080c2d72f222131477444795771577233553637656a7663776d333867396e7a6e7a434b58434b7120a08d0630a696c0b3f78dd9ec083a2131477444795771577233553637656a7663776d333867396e7a6e7a434b58434b71"
in := &types.ReWriteRawTx{
Tx: txHex1,
Execer: []byte("paracross"),
Fee: 29977777777,
Expire: "130s",
To: "aabbccdd",
}
data, err := g.ReWriteRawTx(getOkCtx(), in)
assert.Nil(t, err)
assert.NotNil(t, data.Data)
rtTx := hex.EncodeToString(data.Data)
assert.NotEqual(t, txHex1, rtTx)
tx := &types.Transaction{}
err = types.Decode(data.Data, tx)
assert.Nil(t, err)
assert.Equal(t, tx.Execer, []byte(in.Execer))
assert.Equal(t, tx.Fee, in.Fee)
assert.Equal(t, int64(130000000000), tx.Expire)
assert.Equal(t, in.To, tx.To)
}
...@@ -44,6 +44,24 @@ func (c *Chain33) CreateRawTransaction(in *rpctypes.CreateTx, result *interface{ ...@@ -44,6 +44,24 @@ func (c *Chain33) CreateRawTransaction(in *rpctypes.CreateTx, result *interface{
return nil return nil
} }
// ReWriteRawTx re-write raw tx by jrpc
func (c *Chain33) ReWriteRawTx(in *rpctypes.ReWriteRawTx, result *interface{}) error {
inpb := &types.ReWriteRawTx{
Tx: in.Tx,
Execer: []byte(in.Execer),
To: in.To,
Fee: in.Fee,
Expire: in.Expire,
}
reply, err := c.cli.ReWriteRawTx(inpb)
if err != nil {
return err
}
*result = hex.EncodeToString(reply)
return nil
}
// CreateRawTxGroup create rawtransaction with group // CreateRawTxGroup create rawtransaction with group
func (c *Chain33) CreateRawTxGroup(in *types.CreateTransactionGroup, result *interface{}) error { func (c *Chain33) CreateRawTxGroup(in *types.CreateTransactionGroup, result *interface{}) error {
reply, err := c.cli.CreateRawTxGroup(in) reply, err := c.cli.CreateRawTxGroup(in)
......
...@@ -403,6 +403,36 @@ func TestChain33_CreateRawTransaction(t *testing.T) { ...@@ -403,6 +403,36 @@ func TestChain33_CreateRawTransaction(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestChain33_ReWriteRawTx(t *testing.T) {
api := new(mocks.QueueProtocolAPI)
testChain33 := newTestChain33(api)
txHex1 := "0a05636f696e73122c18010a281080c2d72f222131477444795771577233553637656a7663776d333867396e7a6e7a434b58434b7120a08d0630a696c0b3f78dd9ec083a2131477444795771577233553637656a7663776d333867396e7a6e7a434b58434b71"
//txHex2 := "0a05636f696e73122d18010a29108084af5f222231484c53426e7437486e486a7857797a636a6f573863663259745550663337594d6320a08d0630dbc4cbf6fbc4e1d0533a2231484c53426e7437486e486a7857797a636a6f573863663259745550663337594d63"
reTx := &rpctypes.ReWriteRawTx{
Tx: txHex1,
Execer: "paracross",
Fee: 29977777777,
Expire: "130s",
To: "aabbccdd",
}
var testResult interface{}
err := testChain33.ReWriteRawTx(reTx, &testResult)
assert.Nil(t, err)
assert.NotNil(t, testResult)
assert.NotEqual(t, txHex1, testResult)
txData, err := hex.DecodeString(testResult.(string))
assert.Nil(t, err)
tx := &types.Transaction{}
err = types.Decode(txData, tx)
assert.Nil(t, err)
assert.Equal(t, tx.Execer, []byte(reTx.Execer))
assert.Equal(t, tx.Fee, reTx.Fee)
assert.Equal(t, int64(130000000000), tx.Expire)
assert.Equal(t, reTx.To, tx.To)
}
func TestChain33_CreateTxGroup(t *testing.T) { func TestChain33_CreateTxGroup(t *testing.T) {
api := new(mocks.QueueProtocolAPI) api := new(mocks.QueueProtocolAPI)
testChain33 := newTestChain33(api) testChain33 := newTestChain33(api)
......
...@@ -373,3 +373,12 @@ type CreateTx struct { ...@@ -373,3 +373,12 @@ type CreateTx struct {
ExecName string `json:"execName,omitempty"` //TransferToExec and Withdraw 的执行器 ExecName string `json:"execName,omitempty"` //TransferToExec and Withdraw 的执行器
Execer string `json:"execer,omitempty"` //执行器名称 Execer string `json:"execer,omitempty"` //执行器名称
} }
// ReWriteRawTx parameter
type ReWriteRawTx struct {
Tx string `json:"tx"`
Execer string `json:"execer"`
To string `json:"to"`
Fee int64 `json:"fee"`
Expire string `json:"expire"`
}
...@@ -35,6 +35,7 @@ func TxCmd() *cobra.Command { ...@@ -35,6 +35,7 @@ func TxCmd() *cobra.Command {
GetRawTxCmd(), GetRawTxCmd(),
DecodeTxCmd(), DecodeTxCmd(),
GetAddrOverviewCmd(), GetAddrOverviewCmd(),
ReWriteRawTxCmd(),
) )
return cmd return cmd
...@@ -303,3 +304,50 @@ func parseAddrOverview(view interface{}) (interface{}, error) { ...@@ -303,3 +304,50 @@ func parseAddrOverview(view interface{}) (interface{}, error) {
} }
return addrOverview, nil return addrOverview, nil
} }
// ReWriteRawTxCmd re-write raw transaction hex
func ReWriteRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "rewrite",
Short: "rewrite transaction parameters",
Run: reWriteRawTx,
}
addReWriteRawTxFlags(cmd)
return cmd
}
func addReWriteRawTxFlags(cmd *cobra.Command) {
cmd.Flags().StringP("tx", "s", "", "transaction hex")
cmd.MarkFlagRequired("tx")
cmd.Flags().StringP("execer", "x", "", "transaction execer (optional)")
cmd.Flags().StringP("to", "t", "", "to addr (optional)")
cmd.Flags().Float64P("fee", "f", 0, "transaction fee (optional)")
cmd.Flags().StringP("expire", "e", "120s", "expire time (optional)")
}
func reWriteRawTx(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
txHash, _ := cmd.Flags().GetString("tx")
execer, _ := cmd.Flags().GetString("execer")
to, _ := cmd.Flags().GetString("to")
fee, _ := cmd.Flags().GetFloat64("fee")
expire, _ := cmd.Flags().GetString("expire")
expire, err := commandtypes.CheckExpireOpt(expire)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
feeInt64 := int64(fee * 1e4)
params := rpctypes.ReWriteRawTx{
Tx: txHash,
Execer: execer,
To: to,
Fee: feeInt64 * 1e4,
Expire: expire,
}
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.ReWriteRawTx", params, nil)
ctx.RunWithoutMarshal()
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCheckExpireOpt(t *testing.T) {
expire := "0s"
str, err := CheckExpireOpt(expire)
assert.NoError(t, err)
assert.Equal(t, "0s", str)
expire = "14s"
str, err = CheckExpireOpt(expire)
assert.NoError(t, err)
assert.Equal(t, "120s", str)
expire = "14"
str, err = CheckExpireOpt(expire)
assert.NoError(t, err)
assert.Equal(t, "14", str)
expire = "H:123"
str, err = CheckExpireOpt(expire)
assert.NoError(t, err)
assert.Equal(t, "H:123", str)
}
...@@ -20,7 +20,10 @@ import ( ...@@ -20,7 +20,10 @@ import (
// TODO: 暂时将插件中的类型引用起来,后续需要修改 // TODO: 暂时将插件中的类型引用起来,后续需要修改
"encoding/hex" "encoding/hex"
"errors"
"fmt"
"math" "math"
"time"
) )
// DecodeTransaction decode transaction function // DecodeTransaction decode transaction function
...@@ -156,3 +159,56 @@ func getRealExecName(paraName string, name string) string { ...@@ -156,3 +159,56 @@ func getRealExecName(paraName string, name string) string {
} }
return paraName + name return paraName + name
} }
func parseTxHeight(expire string) error {
if len(expire) == 0 {
return errors.New("expire string should not be empty")
}
if expire[0] == 'H' && expire[1] == ':' {
txHeight, err := strconv.Atoi(expire[2:])
if err != nil {
return err
}
if txHeight <= 0 {
//fmt.Printf("txHeight should be grate to 0")
return errors.New("txHeight should be grate to 0")
}
return nil
}
return errors.New("Invalid expire format. Should be one of {time:\"3600s/1min/1h\" block:\"123\" txHeight:\"H:123\"}")
}
// CheckExpireOpt parse expire option in command
func CheckExpireOpt(expire string) (string, error) {
//时间格式123s/1m/1h
expireTime, err := time.ParseDuration(expire)
if err == nil {
if expireTime < time.Minute*2 && expireTime != time.Second*0 {
expire = "120s"
fmt.Println("expire time must longer than 2 minutes, changed expire time into 2 minutes")
}
return expire, nil
}
//区块高度格式,123
blockInt, err := strconv.Atoi(expire)
if err == nil {
if blockInt <= 0 {
fmt.Printf("block height should be grate to 0")
return "", errors.New("block height should be grate to 0")
}
return expire, nil
}
//Txheight格式,H:123
err = parseTxHeight(expire)
if err != nil {
return "", err
}
return expire, err
}
...@@ -10,8 +10,6 @@ import ( ...@@ -10,8 +10,6 @@ import (
"strconv" "strconv"
"time" "time"
"errors"
"github.com/33cn/chain33/rpc/jsonclient" "github.com/33cn/chain33/rpc/jsonclient"
rpctypes "github.com/33cn/chain33/rpc/types" rpctypes "github.com/33cn/chain33/rpc/types"
commandtypes "github.com/33cn/chain33/system/dapp/commands/types" commandtypes "github.com/33cn/chain33/system/dapp/commands/types"
...@@ -311,6 +309,10 @@ func addSignRawTxFlags(cmd *cobra.Command) { ...@@ -311,6 +309,10 @@ func addSignRawTxFlags(cmd *cobra.Command) {
cmd.Flags().StringP("key", "k", "", "private key (optional)") cmd.Flags().StringP("key", "k", "", "private key (optional)")
cmd.Flags().StringP("addr", "a", "", "account address (optional)") cmd.Flags().StringP("addr", "a", "", "account address (optional)")
cmd.Flags().StringP("expire", "e", "120s", "transaction expire time") cmd.Flags().StringP("expire", "e", "120s", "transaction expire time")
cmd.Flags().Float64P("fee", "f", 0, "transaction fee (optional)")
cmd.Flags().StringP("execer", "x", "", "new transaction execer (optional)")
cmd.Flags().StringP("to", "t", "", "new to addr (optional)")
// A duration string is a possibly signed sequence of // A duration string is a possibly signed sequence of
// decimal numbers, each with optional fraction and a unit suffix, // decimal numbers, each with optional fraction and a unit suffix,
// such as "300ms", "-1.5h" or "2h45m". // such as "300ms", "-1.5h" or "2h45m".
...@@ -342,77 +344,31 @@ func noBalanceTx(cmd *cobra.Command, args []string) { ...@@ -342,77 +344,31 @@ func noBalanceTx(cmd *cobra.Command, args []string) {
ctx.RunWithoutMarshal() ctx.RunWithoutMarshal()
} }
func parseTxHeight(expire string) error {
if len(expire) == 0 {
return errors.New("expire string should not be empty")
}
if expire[0] == 'H' && expire[1] == ':' {
txHeight, err := strconv.Atoi(expire[2:])
if err != nil {
return err
}
if txHeight <= 0 {
//fmt.Printf("txHeight should be grate to 0")
return errors.New("txHeight should be grate to 0")
}
return nil
}
return errors.New("Invalid expire format. Should be one of {time:\"3600s/1min/1h\" block:\"123\" txHeight:\"H:123\"}")
}
func parseExpireOpt(expire string) (string, error) {
//时间格式123s/1m/1h
expireTime, err := time.ParseDuration(expire)
if err == nil {
if expireTime < time.Minute*2 && expireTime != time.Second*0 {
expire = "120s"
fmt.Println("expire time must longer than 2 minutes, changed expire time into 2 minutes")
}
return expire, nil
}
//区块高度格式,123
blockInt, err := strconv.Atoi(expire)
if err == nil {
if blockInt <= 0 {
fmt.Printf("block height should be grate to 0")
return "", errors.New("block height should be grate to 0")
}
return expire, nil
}
//Txheight格式,H:123
err = parseTxHeight(expire)
if err != nil {
return "", err
}
return expire, err
}
func signRawTx(cmd *cobra.Command, args []string) { func signRawTx(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr") rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
data, _ := cmd.Flags().GetString("data") data, _ := cmd.Flags().GetString("data")
key, _ := cmd.Flags().GetString("key") key, _ := cmd.Flags().GetString("key")
addr, _ := cmd.Flags().GetString("addr") addr, _ := cmd.Flags().GetString("addr")
index, _ := cmd.Flags().GetInt32("index") index, _ := cmd.Flags().GetInt32("index")
execer, _ := cmd.Flags().GetString("execer")
to, _ := cmd.Flags().GetString("to")
fee, _ := cmd.Flags().GetFloat64("fee")
expire, _ := cmd.Flags().GetString("expire") expire, _ := cmd.Flags().GetString("expire")
expire, err := parseExpireOpt(expire) expire, err := commandtypes.CheckExpireOpt(expire)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
return return
} }
feeInt64 := int64(fee * 1e4)
params := types.ReqSignRawTx{ params := types.ReqSignRawTx{
Addr: addr, Addr: addr,
Privkey: key, Privkey: key,
TxHex: data, TxHex: data,
Expire: expire, Expire: expire,
Index: index, Index: index,
Fee: feeInt64 * 1e4,
NewExecer: []byte(execer),
NewToAddr: to,
} }
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.SignRawTx", params, nil) ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.SignRawTx", params, nil)
ctx.RunWithoutMarshal() ctx.RunWithoutMarshal()
......
...@@ -22,7 +22,7 @@ type Node struct { ...@@ -22,7 +22,7 @@ type Node struct {
leftNode *Node leftNode *Node
rightHash []byte rightHash []byte
rightNode *Node rightNode *Node
parentHash []byte parentNode *Node
persisted bool persisted bool
} }
...@@ -53,7 +53,6 @@ func MakeNode(buf []byte, t *Tree) (node *Node, err error) { ...@@ -53,7 +53,6 @@ func MakeNode(buf []byte, t *Tree) (node *Node, err error) {
node.height = storeNode.Height node.height = storeNode.Height
node.size = storeNode.Size node.size = storeNode.Size
node.key = storeNode.Key node.key = storeNode.Key
node.parentHash = storeNode.ParentHash
//leaf(叶子节点保存数据) //leaf(叶子节点保存数据)
if node.height == 0 { if node.height == 0 {
...@@ -78,7 +77,7 @@ func (node *Node) _copy() *Node { ...@@ -78,7 +77,7 @@ func (node *Node) _copy() *Node {
leftNode: node.leftNode, leftNode: node.leftNode,
rightHash: node.rightHash, rightHash: node.rightHash,
rightNode: node.rightNode, rightNode: node.rightNode,
parentHash: node.parentHash, parentNode: node.parentNode,
persisted: false, // Going to be mutated, so it can't already be persisted. persisted: false, // Going to be mutated, so it can't already be persisted.
} }
} }
...@@ -185,12 +184,12 @@ func (node *Node) Hash(t *Tree) []byte { ...@@ -185,12 +184,12 @@ func (node *Node) Hash(t *Tree) []byte {
} }
if enablePrune { if enablePrune {
//加入parentHash、brotherHash //加入parentNode
if node.leftNode != nil && node.leftNode.height != t.root.height { //只对倒数第二层做裁剪 if node.leftNode != nil && node.leftNode.height != t.root.height {
node.leftNode.parentHash = node.hash node.leftNode.parentNode = node
} }
if node.rightNode != nil && node.rightNode.height != t.root.height { if node.rightNode != nil && node.rightNode.height != t.root.height {
node.rightNode.parentHash = node.hash node.rightNode.parentNode = node
} }
} }
} }
...@@ -235,7 +234,6 @@ func (node *Node) storeNode(t *Tree) []byte { ...@@ -235,7 +234,6 @@ func (node *Node) storeNode(t *Tree) []byte {
storeNode.Value = nil storeNode.Value = nil
storeNode.LeftHash = nil storeNode.LeftHash = nil
storeNode.RightHash = nil storeNode.RightHash = nil
storeNode.ParentHash = nil
//leafnode //leafnode
if node.height == 0 { if node.height == 0 {
...@@ -255,9 +253,6 @@ func (node *Node) storeNode(t *Tree) []byte { ...@@ -255,9 +253,6 @@ func (node *Node) storeNode(t *Tree) []byte {
} }
storeNode.RightHash = node.rightHash storeNode.RightHash = node.rightHash
} }
if enablePrune {
storeNode.ParentHash = node.parentHash
}
storeNodebytes, err := proto.Marshal(&storeNode) storeNodebytes, err := proto.Marshal(&storeNode)
if err != nil { if err != nil {
panic(err) panic(err)
......
...@@ -9,15 +9,16 @@ import ( ...@@ -9,15 +9,16 @@ import (
"fmt" "fmt"
"sync" "sync"
"sort" "runtime"
"sync/atomic" "sync/atomic"
"time" "time"
"strconv"
"github.com/33cn/chain33/common" "github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db" dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/hashicorp/golang-lru"
) )
const ( const (
...@@ -26,17 +27,16 @@ const ( ...@@ -26,17 +27,16 @@ const (
secLvlPruningHeightKey = "_..mslphk.._" secLvlPruningHeightKey = "_..mslphk.._"
delMapPoolPrefix = "_..md.._" delMapPoolPrefix = "_..md.._"
blockHeightStrLen = 10 blockHeightStrLen = 10
hashLenStr = 3
pruningStateStart = 1 pruningStateStart = 1
pruningStateEnd = 0 pruningStateEnd = 0
//删除节点pool以hash的首字母为key因此有256个
delNodeCacheSize = 256 + 1
//每个del Pool下存放默认4096个hash
perDelNodePoolSize = 4096
//二级裁剪高度,达到此高度未裁剪则放入该处 //二级裁剪高度,达到此高度未裁剪则放入该处
secondLevelPruningHeight = 1000000 secondLevelPruningHeight = 500000
//三级裁剪高度,达到此高度还没有裁剪,则不进行裁剪 //三级裁剪高度,达到此高度还没有裁剪,则不进行裁剪
threeLevelPruningHeight = 1500000 threeLevelPruningHeight = 1500000
onceScanCount = 100000 onceScanCount = 10000 // 单次扫描数目
onceCount = 1000 // 容器长度
batchDataSize = 1024 * 1024 * 1
) )
var ( var (
...@@ -46,40 +46,16 @@ var ( ...@@ -46,40 +46,16 @@ var (
pruneHeight = 10000 pruneHeight = 10000
// 裁剪状态 // 裁剪状态
pruningState int32 pruningState int32
delPoolCache *lru.Cache
wg sync.WaitGroup wg sync.WaitGroup
quit bool quit bool
secLvlPruningH int64 secLvlPruningH int64
) )
func init() {
cache, err := lru.New(delNodeCacheSize)
if err != nil {
panic(fmt.Sprint("new delNodeCache lru fail", err))
}
delPoolCache = cache
}
type delNodeValuePool struct {
delCache *lru.Cache
}
type hashData struct { type hashData struct {
height int64 height int64
hash []byte hash []byte
} }
// newDelNodeValuePool 创建记录已经删除节点缓存池
func newDelNodeValuePool(cacSize int) *delNodeValuePool {
cache, err := lru.New(cacSize)
if err != nil {
return nil
}
dNodePool := &delNodeValuePool{}
dNodePool.delCache = cache
return dNodePool
}
// EnablePrune 使能裁剪 // EnablePrune 使能裁剪
func EnablePrune(enable bool) { func EnablePrune(enable bool) {
enablePrune = enable enablePrune = enable
...@@ -100,38 +76,64 @@ func ClosePrune() { ...@@ -100,38 +76,64 @@ func ClosePrune() {
setPruning(pruningStateStart) setPruning(pruningStateStart)
} }
func genLeafCountKey(key, hash []byte, height int64) (hashkey []byte) { func genLeafCountKey(key, hash []byte, height int64, hashLen int) (hashkey []byte) {
hashkey = []byte(fmt.Sprintf("%s%s%010d%s", leafKeyCountPrefix, string(key), height, string(hash))) hashkey = []byte(fmt.Sprintf("%s%s%010d%s%03d", leafKeyCountPrefix, string(key), height, string(hash), hashLen))
return hashkey return hashkey
} }
func getKeyFromLeafCountKey(hashkey []byte, hashlen int) ([]byte, error) { func getKeyHeightFromLeafCountKey(hashkey []byte) (key []byte, height int, hash []byte, err error) {
if len(hashkey) <= len(leafKeyCountPrefix)+hashlen+blockHeightStrLen { if len(hashkey) < len(leafKeyCountPrefix)+blockHeightStrLen+len(common.Hash{})+hashLenStr {
return nil, types.ErrSize return nil, 0, nil, types.ErrSize
} }
if !bytes.Contains(hashkey, []byte(leafKeyCountPrefix)) { if !bytes.Contains(hashkey, []byte(leafKeyCountPrefix)) {
return nil, types.ErrSize return nil, 0, nil, types.ErrSize
}
sLen := hashkey[len(hashkey)-hashLenStr:]
iLen, err := strconv.Atoi(string(sLen))
if err != nil {
return nil, 0, nil, types.ErrSize
} }
k := bytes.TrimPrefix(hashkey, []byte(leafKeyCountPrefix)) k := bytes.TrimPrefix(hashkey, []byte(leafKeyCountPrefix))
k = k[:len(k)-hashlen-blockHeightStrLen] key = k[:len(k)-iLen-blockHeightStrLen-hashLenStr]
return k, nil //keyHeighthash
heightHash := k[len(key) : len(k)-hashLenStr]
sHeight := heightHash[:blockHeightStrLen]
height, err = strconv.Atoi(string(sHeight))
if err != nil {
return nil, 0, nil, types.ErrSize
}
hash = heightHash[blockHeightStrLen:]
return key, height, hash, nil
} }
func genOldLeafCountKey(key, hash []byte, height int64) (hashkey []byte) { func genOldLeafCountKey(key, hash []byte, height int64, hashLen int) (hashkey []byte) {
hashkey = []byte(fmt.Sprintf("%s%s%010d%s", oldLeafKeyCountPrefix, string(key), height, string(hash))) hashkey = []byte(fmt.Sprintf("%s%s%010d%s%03d", oldLeafKeyCountPrefix, string(key), height, string(hash), hashLen))
return hashkey return hashkey
} }
func getKeyFromOldLeafCountKey(hashkey []byte, hashlen int) ([]byte, error) { func getKeyHeightFromOldLeafCountKey(hashkey []byte) (key []byte, height int, hash []byte, err error) {
if len(hashkey) <= len(oldLeafKeyCountPrefix)+hashlen+blockHeightStrLen { if len(hashkey) < len(oldLeafKeyCountPrefix)+blockHeightStrLen+len(common.Hash{})+hashLenStr {
return nil, types.ErrSize return nil, 0, nil, types.ErrSize
} }
if !bytes.Contains(hashkey, []byte(oldLeafKeyCountPrefix)) { if !bytes.Contains(hashkey, []byte(oldLeafKeyCountPrefix)) {
return nil, types.ErrSize return nil, 0, nil, types.ErrSize
}
sLen := hashkey[len(hashkey)-hashLenStr:]
iLen, err := strconv.Atoi(string(sLen))
if err != nil {
return nil, 0, nil, types.ErrSize
} }
k := bytes.TrimPrefix(hashkey, []byte(oldLeafKeyCountPrefix)) k := bytes.TrimPrefix(hashkey, []byte(oldLeafKeyCountPrefix))
k = k[:len(k)-hashlen-blockHeightStrLen] key = k[:len(k)-iLen-blockHeightStrLen-hashLenStr]
return k, nil //keyHeighthash
heightHash := k[len(key) : len(k)-hashLenStr]
sHeight := heightHash[:blockHeightStrLen]
height, err = strconv.Atoi(string(sHeight))
if err != nil {
return nil, 0, nil, types.ErrSize
}
hash = heightHash[blockHeightStrLen:]
return key, height, hash, nil
} }
func genOldLeafCountKeyFromKey(hashk []byte) (oldhashk []byte) { func genOldLeafCountKeyFromKey(hashk []byte) (oldhashk []byte) {
...@@ -142,21 +144,6 @@ func genOldLeafCountKeyFromKey(hashk []byte) (oldhashk []byte) { ...@@ -142,21 +144,6 @@ func genOldLeafCountKeyFromKey(hashk []byte) (oldhashk []byte) {
return oldhashk return oldhashk
} }
func genDeletePoolKey(hash []byte) (key, value []byte) {
if len(hash) < 32 {
panic("genDeletePoolKey error hash len illegal")
}
hashLen := len(common.Hash{})
if len(hash) > hashLen {
value = hash[len(hash)-hashLen:]
} else {
value = hash
}
key = value[:1]
key = []byte(fmt.Sprintf("%s%s", delMapPoolPrefix, string(key)))
return key, value
}
func isPruning() bool { func isPruning() bool {
return atomic.LoadInt32(&pruningState) == 1 return atomic.LoadInt32(&pruningState) == 1
} }
...@@ -212,32 +199,31 @@ func pruningFirstLevelNode(db dbm.DB, curHeight int64) { ...@@ -212,32 +199,31 @@ func pruningFirstLevelNode(db dbm.DB, curHeight int64) {
it := db.Iterator(prefix, nil, true) it := db.Iterator(prefix, nil, true)
defer it.Close() defer it.Close()
mp := make(map[string][]hashData) var mp map[string][]hashData
var kvs []*types.KeyValue var kvs []*types.KeyValue
count := 0 count := 0
batch := db.NewBatch(true)
for it.Rewind(); it.Valid(); it.Next() { for it.Rewind(); it.Valid(); it.Next() {
if quit { if quit {
//该处退出 //该处退出
return return
} }
if mp == nil {
mp = make(map[string][]hashData, onceCount)
}
//copy key //copy key
hashK := make([]byte, len(it.Key())) hashK := make([]byte, len(it.Key()))
copy(hashK, it.Key()) copy(hashK, it.Key())
value := it.Value() key, height, hash, err := getKeyHeightFromLeafCountKey(hashK)
var pData types.PruneData
err := proto.Unmarshal(value, &pData)
if err != nil { if err != nil {
panic("Unmarshal mavl leafCountKey fail") continue
} }
var key []byte if curHeight < int64(height)+secondLevelPruningHeight {
if curHeight < pData.Height+secondLevelPruningHeight { if curHeight >= int64(height)+int64(pruneHeight) {
hashLen := int(pData.Lenth)
key, err = getKeyFromLeafCountKey(hashK, hashLen)
if err == nil {
data := hashData{ data := hashData{
height: pData.Height, height: int64(height),
hash: hashK[len(hashK)-hashLen:], hash: hash,
} }
mp[string(key)] = append(mp[string(key)], data) mp[string(key)] = append(mp[string(key)], data)
count++ count++
...@@ -247,54 +233,64 @@ func pruningFirstLevelNode(db dbm.DB, curHeight int64) { ...@@ -247,54 +233,64 @@ func pruningFirstLevelNode(db dbm.DB, curHeight int64) {
copy(value, it.Value()) copy(value, it.Value())
kvs = append(kvs, &types.KeyValue{Key: hashK, Value: value}) kvs = append(kvs, &types.KeyValue{Key: hashK, Value: value})
} }
if count >= onceScanCount { if len(mp) >= onceCount-1 || count > onceScanCount {
deleteNode(db, mp, curHeight, key) deleteNode(db, mp, curHeight, batch)
mp = nil
count = 0 count = 0
} }
if len(kvs) >= onceScanCount/2 { if len(kvs) >= onceCount {
addLeafCountKeyToSecondLevel(db, kvs) addLeafCountKeyToSecondLevel(db, kvs, batch)
kvs = kvs[:0] kvs = kvs[:0]
} }
} }
if count > 0 { if len(mp) > 0 {
deleteNode(db, mp, curHeight, nil) deleteNode(db, mp, curHeight, batch)
mp = nil
_ = mp
} }
if len(kvs) > 0 { if len(kvs) > 0 {
addLeafCountKeyToSecondLevel(db, kvs) addLeafCountKeyToSecondLevel(db, kvs, batch)
} }
} }
func addLeafCountKeyToSecondLevel(db dbm.DB, kvs []*types.KeyValue) { func addLeafCountKeyToSecondLevel(db dbm.DB, kvs []*types.KeyValue, batch dbm.Batch) {
batch := db.NewBatch(true) batch.Reset()
for _, kv := range kvs { for _, kv := range kvs {
batch.Delete(kv.Key) batch.Delete(kv.Key)
batch.Set(genOldLeafCountKeyFromKey(kv.Key), kv.Value) batch.Set(genOldLeafCountKeyFromKey(kv.Key), kv.Value)
if batch.ValueSize() > batchDataSize {
batch.Write()
batch.Reset()
}
} }
batch.Write() batch.Write()
} }
func deleteNode(db dbm.DB, mp map[string][]hashData, curHeight int64, lastKey []byte) { func deleteNode(db dbm.DB, mp map[string][]hashData, curHeight int64, batch dbm.Batch) {
if len(mp) == 0 { if len(mp) == 0 {
return return
} }
var tmp []hashData batch.Reset()
//del
if lastKey != nil {
if _, ok := mp[string(lastKey)]; ok {
tmp = mp[string(lastKey)]
delete(mp, string(lastKey))
}
}
delMp := make(map[string]bool)
batch := db.NewBatch(true)
for key, vals := range mp { for key, vals := range mp {
if len(vals) > 1 { if len(vals) > 1 && vals[1].height != vals[0].height { //防止相同高度时候出现的误删除
if vals[1].height != vals[0].height { //防止相同高度时候出现的误删除 for _, val := range vals[1:] { //从第二个开始判断
for _, val := range vals[1:] { //从第二个开始判断 if curHeight >= val.height+int64(pruneHeight) {
if curHeight >= val.height+int64(pruneHeight) { leafCountKey := genLeafCountKey([]byte(key), val.hash, val.height, len(val.hash))
//batch.Delete(val.hash) //叶子节点hash值的删除放入pruningHashNode中 value, err := db.Get(leafCountKey)
batch.Delete(genLeafCountKey([]byte(key), val.hash, val.height)) if err == nil {
delMp[string(val.hash)] = true var pData types.PruneData
err := proto.Unmarshal(value, &pData)
if err == nil {
for _, hash := range pData.Hashs {
batch.Delete(hash)
}
}
}
batch.Delete(leafCountKey) // 叶子计数节点
batch.Delete(val.hash) // 叶子节点hash值
if batch.ValueSize() > batchDataSize {
batch.Write()
batch.Reset()
} }
} }
} }
...@@ -302,255 +298,6 @@ func deleteNode(db dbm.DB, mp map[string][]hashData, curHeight int64, lastKey [] ...@@ -302,255 +298,6 @@ func deleteNode(db dbm.DB, mp map[string][]hashData, curHeight int64, lastKey []
delete(mp, key) delete(mp, key)
} }
batch.Write() batch.Write()
//add
if lastKey != nil {
if _, ok := mp[string(lastKey)]; ok {
mp[string(lastKey)] = tmp
}
}
//裁剪hashNode
pruningHashNode(db, delMp)
}
func pruningHashNode(db dbm.DB, mp map[string]bool) {
if len(mp) == 0 {
return
}
//对mp排序
sortKeys := make([]string, len(mp)+1)
for key := range mp {
sortKeys = append(sortKeys, key)
}
sort.Strings(sortKeys)
ndb := newMarkNodeDB(db, 1024*10)
var delNodeStrs []string
for _, key := range sortKeys {
mNode, err := ndb.LoadLeaf([]byte(key))
if err == nil {
delNodeStrs = append(delNodeStrs, mNode.getHashNode(ndb)...)
}
}
//根据keyMap进行归类
mpAddDel := make(map[string][][]byte)
for _, s := range delNodeStrs {
key, hash := genDeletePoolKey([]byte(s))
mpAddDel[string(key)] = append(mpAddDel[string(key)], hash)
}
//更新pool数据
batch := db.NewBatch(true)
for mpk, mpV := range mpAddDel {
dep := ndb.getPool(mpk)
if dep != nil {
for _, aHsh := range mpV {
dep.delCache.Add(string(aHsh), true)
}
ndb.updateDelHash(batch, mpk, dep)
}
}
batch.Write()
//加入要删除的hash节点
count1 := 0
for _, str := range delNodeStrs {
mp[str] = true
count1++
}
count := 0
batch = db.NewBatch(true)
for key := range mp {
batch.Delete([]byte(key))
count++
}
batch.Write()
//fmt.Printf("pruningHashNode ndb.count %d delete %d \n", ndb.count, count1)
treelog.Info("pruningHashNode ", "delNodeStrs", count1, "delete node mp count", count)
}
//获取要删除的hash节点
func (node *MarkNode) getHashNode(ndb *markNodeDB) (delNodeStrs []string) {
for {
parN := node.fetchParentNode(ndb)
if parN != nil {
delNodeStrs = append(delNodeStrs, string(node.hash))
node = parN
} else {
delNodeStrs = append(delNodeStrs, string(node.hash))
break
}
}
return delNodeStrs
}
func (ndb *markNodeDB) updateDelHash(batch dbm.Batch, key string, dep *delNodeValuePool) {
if dep == nil {
return
}
//这里指针暂时不需要赋值
//if ndb.delPoolCache != nil {
// ndb.delPoolCache.Add(key, dep)
//}
stp := &types.StoreValuePool{}
for _, k := range dep.delCache.Keys() {
stp.Values = append(stp.Values, []byte(k.(string)))
}
v, err := proto.Marshal(stp)
if err != nil {
panic(fmt.Sprint("types.DeleteNodeMap fail", err))
}
batch.Set([]byte(key), v)
}
func (ndb *markNodeDB) getPool(str string) (dep *delNodeValuePool) {
if ndb.delPoolCache != nil {
elem, ok := ndb.delPoolCache.Get(str)
if ok {
dep = elem.(*delNodeValuePool)
return dep
}
}
v, err := ndb.db.Get([]byte(str))
if err != nil || len(v) == 0 {
//如果不存在说明是新的则
//创建一个空的集
ndb.judgeDelNodeCache()
dep = newDelNodeValuePool(perDelNodePoolSize)
if dep != nil {
ndb.delPoolCache.Add(str, dep)
}
} else {
stp := &types.StoreValuePool{}
err = proto.Unmarshal(v, stp)
if err != nil {
panic(fmt.Sprint("types.StoreValuePool fail", err))
}
if ndb.delPoolCache != nil {
ndb.judgeDelNodeCache()
dep = newDelNodeValuePool(perDelNodePoolSize)
if dep != nil {
for _, k := range stp.Values {
dep.delCache.Add(string(k), true)
}
ndb.delPoolCache.Add(str, dep)
}
}
}
return dep
}
func (ndb *markNodeDB) judgeDelNodeCache() {
if ndb.delPoolCache.Len() >= delNodeCacheSize {
strs := ndb.delPoolCache.Keys()
elem, ok := ndb.delPoolCache.Get(strs[0])
if ok {
mp := elem.(*delNodeValuePool)
stp := &types.StoreValuePool{}
for _, k := range mp.delCache.Keys() {
stp.Values = append(stp.Values, []byte(k.(string)))
}
v, err := proto.Marshal(stp)
if err != nil {
panic(fmt.Sprint("types.StoreValuePool fail", err))
}
ndb.db.Set([]byte(strs[0].(string)), v)
}
}
}
// MarkNode 用于裁剪的节点结构体
type MarkNode struct {
height int32
hash []byte
leftHash []byte
rightHash []byte
parentHash []byte
parentNode *MarkNode
}
type markNodeDB struct {
//mtx sync.Mutex
cache *lru.Cache // 缓存当前批次已经删除的节点,
delPoolCache *lru.Cache // 缓存全部的已经删除的节点
db dbm.DB
}
func newMarkNodeDB(db dbm.DB, cache int) *markNodeDB {
cach, _ := lru.New(cache)
ndb := &markNodeDB{
cache: cach,
delPoolCache: delPoolCache,
db: db,
}
return ndb
}
// LoadLeaf 载入叶子节点
func (ndb *markNodeDB) LoadLeaf(hash []byte) (node *MarkNode, err error) {
if !bytes.Equal(hash, emptyRoot[:]) {
leaf, err := ndb.fetchNode(hash)
return leaf, err
}
return nil, types.ErrNotFound
}
func (node *MarkNode) fetchParentNode(ndb *markNodeDB) *MarkNode {
if node.parentNode != nil {
return node.parentNode
}
pNode, err := ndb.fetchNode(node.parentHash)
if err != nil {
return nil
}
return pNode
}
func (ndb *markNodeDB) fetchNode(hash []byte) (*MarkNode, error) {
if len(hash) == 0 {
return nil, ErrNodeNotExist
}
//ndb.mtx.Lock()
//defer ndb.mtx.Unlock()
var mNode *MarkNode
// cache
if ndb.cache != nil {
_, ok := ndb.cache.Get(string(hash))
if ok {
//缓存已经删除的节点,
return nil, ErrNodeNotExist
}
}
if mNode == nil {
// 先判断是否已经删除掉,如果删除掉查找比较耗时
key, hsh := genDeletePoolKey(hash)
mp := ndb.getPool(string(key))
if mp != nil {
if _, ok := mp.delCache.Get(string(hsh)); ok {
return nil, ErrNodeNotExist
}
}
var buf []byte
buf, err := ndb.db.Get(hash)
if len(buf) == 0 || err != nil {
return nil, err
}
node, err := MakeNode(buf, nil)
if err != nil {
panic(fmt.Sprintf("Error reading IAVLNode. bytes: %X error: %v", buf, err))
}
node.hash = hash
mNode = &MarkNode{
height: node.height,
hash: node.hash,
leftHash: node.leftHash,
rightHash: node.rightHash,
parentHash: node.parentHash,
}
if ndb.cache != nil {
ndb.cache.Add(string(hash), mNode)
}
}
return mNode, nil
} }
func pruningSecondLevel(db dbm.DB, curHeight int64) { func pruningSecondLevel(db dbm.DB, curHeight int64) {
...@@ -574,88 +321,85 @@ func pruningSecondLevelNode(db dbm.DB, curHeight int64) { ...@@ -574,88 +321,85 @@ func pruningSecondLevelNode(db dbm.DB, curHeight int64) {
it := db.Iterator(prefix, nil, true) it := db.Iterator(prefix, nil, true)
defer it.Close() defer it.Close()
mp := make(map[string][]hashData) var mp map[string][]hashData
count := 0 count := 0
batch := db.NewBatch(true)
for it.Rewind(); it.Valid(); it.Next() { for it.Rewind(); it.Valid(); it.Next() {
if quit { if quit {
//该处退出 //该处退出
return return
} }
if mp == nil {
mp = make(map[string][]hashData, onceCount)
}
//copy key //copy key
hashK := make([]byte, len(it.Key())) hashK := make([]byte, len(it.Key()))
copy(hashK, it.Key()) copy(hashK, it.Key())
key, height, hash, err := getKeyHeightFromOldLeafCountKey(hashK)
value := it.Value()
var pData types.PruneData
err := proto.Unmarshal(value, &pData)
if err != nil {
panic("Unmarshal mavl leafCountKey fail")
}
hashLen := int(pData.Lenth)
key, err := getKeyFromOldLeafCountKey(hashK, hashLen)
if err == nil { if err == nil {
data := hashData{ data := hashData{
height: pData.Height, height: int64(height),
hash: hashK[len(hashK)-hashLen:], hash: hash,
} }
mp[string(key)] = append(mp[string(key)], data) mp[string(key)] = append(mp[string(key)], data)
count++ count++
if count >= onceScanCount { if len(mp) >= onceCount-1 || count > onceScanCount {
deleteOldNode(db, mp, curHeight, key) deleteOldNode(db, mp, curHeight, batch)
mp = nil
count = 0 count = 0
} }
} }
} }
if count > 0 { if len(mp) > 0 {
deleteOldNode(db, mp, curHeight, nil) deleteOldNode(db, mp, curHeight, batch)
mp = nil
_ = mp
} }
} }
func deleteOldNode(db dbm.DB, mp map[string][]hashData, curHeight int64, lastKey []byte) { func deleteOldNode(db dbm.DB, mp map[string][]hashData, curHeight int64, batch dbm.Batch) {
if len(mp) == 0 { if len(mp) == 0 {
return return
} }
var tmp []hashData batch.Reset()
//del
if lastKey != nil {
if _, ok := mp[string(lastKey)]; ok {
tmp = mp[string(lastKey)]
delete(mp, string(lastKey))
}
}
delMp := make(map[string]bool)
batch := db.NewBatch(true)
for key, vals := range mp { for key, vals := range mp {
if len(vals) > 1 { if len(vals) > 1 {
if vals[1].height != vals[0].height { //防止相同高度时候出现的误删除 if vals[1].height != vals[0].height { //防止相同高度时候出现的误删除
for _, val := range vals[1:] { //从第二个开始判断 for _, val := range vals[1:] { //从第二个开始判断
if curHeight >= val.height+int64(pruneHeight) { if curHeight >= val.height+int64(pruneHeight) {
batch.Delete(genOldLeafCountKey([]byte(key), val.hash, val.height)) leafCountKey := genOldLeafCountKey([]byte(key), val.hash, val.height, len(val.hash))
delMp[string(val.hash)] = true value, err := db.Get(leafCountKey)
if err == nil {
var pData types.PruneData
err := proto.Unmarshal(value, &pData)
if err == nil {
for _, hash := range pData.Hashs {
batch.Delete(hash)
}
}
}
batch.Delete(leafCountKey)
batch.Delete(val.hash) // 叶子节点hash值
} }
} }
} else { } else {
// 删除第三层存储索引key // 删除第三层存储索引key
for _, val := range vals { for _, val := range vals {
if curHeight >= val.height+threeLevelPruningHeight { if curHeight >= val.height+threeLevelPruningHeight {
batch.Delete(genOldLeafCountKey([]byte(key), val.hash, val.height)) batch.Delete(genOldLeafCountKey([]byte(key), val.hash, val.height, len(val.hash)))
} }
} }
} }
} else if len(vals) == 1 && curHeight >= vals[0].height+threeLevelPruningHeight { // 删除第三层存储索引key } else if len(vals) == 1 && curHeight >= vals[0].height+threeLevelPruningHeight { // 删除第三层存储索引key
batch.Delete(genLeafCountKey([]byte(key), vals[0].hash, vals[0].height)) batch.Delete(genOldLeafCountKey([]byte(key), vals[0].hash, vals[0].height, len(vals[0].hash)))
} }
delete(mp, key) delete(mp, key)
} if batch.ValueSize() > batchDataSize {
batch.Write() batch.Write()
//add batch.Reset()
if lastKey != nil {
if _, ok := mp[string(lastKey)]; ok {
mp[string(lastKey)] = tmp
} }
} }
//裁剪hashNode batch.Write()
pruningHashNode(db, delMp)
} }
// PruningTreePrintDB pruning tree print db // PruningTreePrintDB pruning tree print db
...@@ -670,10 +414,9 @@ func PruningTreePrintDB(db dbm.DB, prefix []byte) { ...@@ -670,10 +414,9 @@ func PruningTreePrintDB(db dbm.DB, prefix []byte) {
var pData types.PruneData var pData types.PruneData
err := proto.Unmarshal(value, &pData) err := proto.Unmarshal(value, &pData)
if err == nil { if err == nil {
hashLen := int(pData.Lenth) key, height, _, err := getKeyHeightFromLeafCountKey(hashK)
key, err := getKeyFromLeafCountKey(hashK, hashLen)
if err == nil { if err == nil {
treelog.Debug("pruningTree:", "key:", string(key), "height", pData.Height) treelog.Debug("pruningTree:", "key:", string(key), "height", height)
} }
} }
} else if bytes.Equal(prefix, []byte(hashNodePrefix)) { } else if bytes.Equal(prefix, []byte(hashNodePrefix)) {
...@@ -700,3 +443,10 @@ func PruningTreePrintDB(db dbm.DB, prefix []byte) { ...@@ -700,3 +443,10 @@ func PruningTreePrintDB(db dbm.DB, prefix []byte) {
func PruningTree(db dbm.DB, curHeight int64) { func PruningTree(db dbm.DB, curHeight int64) {
pruningTree(db, curHeight) pruningTree(db, curHeight)
} }
// PrintMemStats 打印内存使用情况
func PrintMemStats(height int64) {
var m runtime.MemStats
runtime.ReadMemStats(&m)
treelog.Info("printMemStats:", "程序向系统申请", m.HeapSys/(1024*1024), "堆上目前分配Alloc:", m.HeapAlloc/(1024*1024), "堆上没有使用", m.HeapIdle/(1024*1024), "HeapReleased", m.HeapReleased/(1024*1024), "height", height)
}
...@@ -317,6 +317,23 @@ func (ndb *nodeDB) GetBatch(sync bool) *nodeBatch { ...@@ -317,6 +317,23 @@ func (ndb *nodeDB) GetBatch(sync bool) *nodeBatch {
return &nodeBatch{ndb.db.NewBatch(sync)} return &nodeBatch{ndb.db.NewBatch(sync)}
} }
// 获取叶子节点的所有父节点
func getHashNode(node *Node) (hashs [][]byte) {
for {
if node == nil {
return
}
parN := node.parentNode
if parN != nil {
hashs = append(hashs, parN.hash)
node = parN
} else {
break
}
}
return hashs
}
// SaveNode 保存节点 // SaveNode 保存节点
func (ndb *nodeDB) SaveNode(t *Tree, node *Node) { func (ndb *nodeDB) SaveNode(t *Tree, node *Node) {
ndb.mtx.Lock() ndb.mtx.Lock()
...@@ -333,10 +350,9 @@ func (ndb *nodeDB) SaveNode(t *Tree, node *Node) { ...@@ -333,10 +350,9 @@ func (ndb *nodeDB) SaveNode(t *Tree, node *Node) {
ndb.batch.Set(node.hash, storenode) ndb.batch.Set(node.hash, storenode)
if enablePrune && node.height == 0 { if enablePrune && node.height == 0 {
//save leafnode key&hash //save leafnode key&hash
k := genLeafCountKey(node.key, node.hash, t.blockHeight) k := genLeafCountKey(node.key, node.hash, t.blockHeight, len(node.hash))
data := &types.PruneData{ data := &types.PruneData{
Height: t.blockHeight, Hashs: getHashNode(node),
Lenth: int32(len(node.hash)),
} }
v, err := proto.Marshal(data) v, err := proto.Marshal(data)
if err != nil { if err != nil {
......
...@@ -19,6 +19,7 @@ import ( ...@@ -19,6 +19,7 @@ import (
"github.com/33cn/chain33/common/db" "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/log" "github.com/33cn/chain33/common/log"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
...@@ -874,150 +875,419 @@ func TestMaxLevalDbValue(t *testing.T) { ...@@ -874,150 +875,419 @@ func TestMaxLevalDbValue(t *testing.T) {
} }
} }
func TestPruningHashNode(t *testing.T) { func TestPruningFirstLevelNode(t *testing.T) {
//开启前缀时候需要加入在叶子节点hash上加入:5f6d625f2d303030303030303030302d
/* 叶子节点对应hash值
k:abc v:abc hash:0xd95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44d
k:fan v:fan hash:0x3bf26d01cb0752bcfd60b72348a8fde671f32f51ec276606cd5f35658c172114
k:foml v:foml hash:0x0ac69b0f4ceee514d09f2816e387cda870c06be28b50bf416de5c0ba90cdfbc0
k:foo v:foo hash:0x890d4f4450d5ea213b8e63aae98fae548f210b5c8d3486b685cfa86adde16ec2
k:foobang v:foobang hash:0x6d46d71882171840bcb61f2b60b69c904a4c30435bf03e63f4ec36bfa47ab2be
k:foobar v:foobar hash:0x5308d1f9b60e831a5df663babbf2a2636ecaf4da3bffed52447faf5ab172cf93
k:foobaz v:foobaz hash:0xcbcb48848f0ce209cfccdf3ddf80740915c9bdede3cb11d0378690ad8b85a68b
k:food v:food hash:0xe5080908c794168285a090088ae892793d549f3e7069f4feae3677bf3a28ad39
k:good v:good hash:0x0c99238587914476198da04cbb1555d092f813eaf2e796893084406290188776
k:low v:low hash:0x5a82d9685c0627c94ac5ba13e819c60e05b577bf6512062cf3dc2b5d9b381786
height:0 hash:d95f left: right: parentHash:967b
height:0 hash:3bf2 left: right: parentHash:cf1e
height:0 hash:0ac6 left: right: parentHash:cf1e
height:1 hash:cf1e left:3bf2 right:0ac6 parentHash:
height:2 hash:967b left:d95f right:cf1e parentHash:
height:0 hash:890d left: right: parentHash:c0bf
height:0 hash:6d46 left: right: parentHash:2f47
height:0 hash:5308 left: right: parentHash:2f47
height:1 hash:2f47 left:6d46 right:5308 parentHash:
height:2 hash:c0bf left:890d right:2f47 parentHash:
height:3 hash:d556 left:967b right:c0bf parentHash:
height:0 hash:cbcb left: right: parentHash:121e
height:0 hash:e508 left: right: parentHash:121e
height:1 hash:121e left:cbcb right:e508 parentHash:
height:0 hash:0c99 left: right: parentHash:00ab
height:0 hash:5a82 left: right: parentHash:00ab
height:1 hash:00ab left:0c99 right:5a82 parentHash:
height:2 hash:5202 left:121e right:00ab parentHash:
height:4 hash:1134 left:d556 right:5202 parentHash:
*/
dir, err := ioutil.TempDir("", "datastore") dir, err := ioutil.TempDir("", "datastore")
require.NoError(t, err) require.NoError(t, err)
t.Log(dir) t.Log(dir)
defer os.RemoveAll(dir)
db1 := db.NewDB("mavltree", "leveldb", dir, 100)
//add node data
nodes1 := []Node{
{key: []byte("11111111"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44d"), height: 1},
{key: []byte("11111111"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44a"), height: 5000},
{key: []byte("11111111"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44b"), height: 10000},
{key: []byte("11111111"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44c"), height: 30000},
{key: []byte("11111111"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44e"), height: 40000},
{key: []byte("11111111"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44f"), height: 450000},
}
nodes2 := []Node{
{key: []byte("22222222"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc45d"), height: 1},
{key: []byte("22222222"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc45a"), height: 5000},
{key: []byte("22222222"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc45b"), height: 10000},
{key: []byte("22222222"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc45c"), height: 30000},
{key: []byte("22222222"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc45e"), height: 40000},
{key: []byte("22222222"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc45f"), height: 450000},
}
hashNodes1 := []types.PruneData{
{Hashs: [][]byte{[]byte("113"), []byte("114"), []byte("115"), []byte("116"), []byte("117"), []byte("118")}},
{Hashs: [][]byte{[]byte("123"), []byte("124"), []byte("125"), []byte("126"), []byte("127"), []byte("128")}},
{Hashs: [][]byte{[]byte("133"), []byte("134"), []byte("135"), []byte("136"), []byte("137"), []byte("138")}},
{Hashs: [][]byte{[]byte("143"), []byte("144"), []byte("145"), []byte("146"), []byte("147"), []byte("148")}},
{Hashs: [][]byte{[]byte("153"), []byte("154"), []byte("155"), []byte("156"), []byte("157"), []byte("158")}},
{Hashs: [][]byte{[]byte("163"), []byte("164"), []byte("165"), []byte("166"), []byte("167"), []byte("168")}},
}
hashNodes2 := []types.PruneData{
{Hashs: [][]byte{[]byte("213"), []byte("214"), []byte("215"), []byte("216"), []byte("217"), []byte("218")}},
{Hashs: [][]byte{[]byte("223"), []byte("224"), []byte("225"), []byte("226"), []byte("227"), []byte("228")}},
{Hashs: [][]byte{[]byte("233"), []byte("234"), []byte("235"), []byte("236"), []byte("237"), []byte("238")}},
{Hashs: [][]byte{[]byte("243"), []byte("244"), []byte("245"), []byte("246"), []byte("247"), []byte("248")}},
{Hashs: [][]byte{[]byte("253"), []byte("254"), []byte("255"), []byte("256"), []byte("257"), []byte("258")}},
{Hashs: [][]byte{[]byte("263"), []byte("264"), []byte("265"), []byte("266"), []byte("267"), []byte("268")}},
}
batch := db1.NewBatch(true)
for i, node := range nodes1 {
k := genLeafCountKey(node.key, node.hash, int64(node.height), len(node.hash))
data := &types.PruneData{
Hashs: hashNodes1[i].Hashs,
}
v, err := proto.Marshal(data)
if err != nil {
panic(err)
}
// 保存索引节点
batch.Set(k, v)
// 保存叶子节点
batch.Set(node.hash, node.key)
// 保存hash节点
for _, hash := range data.Hashs {
batch.Set(hash, hash)
}
}
for i, node := range nodes2 {
k := genLeafCountKey(node.key, node.hash, int64(node.height), len(node.hash))
data := &types.PruneData{
Hashs: hashNodes2[i].Hashs,
}
v, err := proto.Marshal(data)
if err != nil {
panic(err)
}
// 保存索引节点
batch.Set(k, v)
// 保存叶子节点
batch.Set(node.hash, node.key)
// 保存hash节点
for _, hash := range data.Hashs {
batch.Set(hash, hash)
}
}
batch.Write()
db1.Close()
EnableMavlPrefix(true) SetPruneHeight(5000)
defer EnableMavlPrefix(false) db2 := db.NewDB("mavltree", "leveldb", dir, 100)
EnablePrune(true)
defer EnablePrune(false)
db := db.NewDB("mavltree", "leveldb", dir, 100) var existHashs [][]byte
tree := NewTree(db, true) var noExistHashs [][]byte
type record struct { //当前高度设置为10000,只能删除高度为1的节点
key string pruningFirstLevel(db2, 10000)
value string
for i, node := range nodes1 {
if i >= 1 {
existHashs = append(existHashs, node.hash)
existHashs = append(existHashs, hashNodes1[i].Hashs...)
} else {
noExistHashs = append(noExistHashs, node.hash)
noExistHashs = append(noExistHashs, hashNodes1[i].Hashs...)
}
} }
records := []record{ for i, node := range nodes2 {
{"abc", "abc"}, if i >= 1 {
{"low", "low"}, existHashs = append(existHashs, node.hash)
{"fan", "fan"}, existHashs = append(existHashs, hashNodes1[i].Hashs...)
{"foo", "foo"}, } else {
{"foobaz", "foobaz"}, noExistHashs = append(noExistHashs, node.hash)
{"good", "good"}, noExistHashs = append(noExistHashs, hashNodes1[i].Hashs...)
//{"foobang", "foobang"}, }
//{"foobar", "foobar"},
//{"food", "food"},
//{"foml", "foml"},
} }
verifyNodeExist(t, db2, existHashs, noExistHashs)
keys := make([]string, len(records)) //当前高度设置为20000, 删除高度为1000的
for i, r := range records { pruningFirstLevel(db2, 20000)
keys[i] = r.key
existHashs = existHashs[:0][:0]
existHashs = noExistHashs[:0][:0]
for i, node := range nodes1 {
if i >= 2 {
existHashs = append(existHashs, node.hash)
existHashs = append(existHashs, hashNodes1[i].Hashs...)
} else {
noExistHashs = append(noExistHashs, node.hash)
noExistHashs = append(noExistHashs, hashNodes1[i].Hashs...)
}
} }
sort.Strings(keys) for i, node := range nodes2 {
if i >= 2 {
existHashs = append(existHashs, node.hash)
existHashs = append(existHashs, hashNodes1[i].Hashs...)
} else {
noExistHashs = append(noExistHashs, node.hash)
noExistHashs = append(noExistHashs, hashNodes1[i].Hashs...)
}
}
verifyNodeExist(t, db2, existHashs, noExistHashs)
//目前还剩下 10000 30000 40000 450000
//当前高度设置为510001, 将高度为10000的加入二级节点,删除30000 40000节点
pruningFirstLevel(db2, 510001)
existHashs = existHashs[:0][:0]
existHashs = noExistHashs[:0][:0]
for i, node := range nodes1 {
if i >= 5 {
existHashs = append(existHashs, node.hash)
existHashs = append(existHashs, hashNodes1[i].Hashs...)
} else if i == 2 {
} else {
noExistHashs = append(noExistHashs, node.hash)
noExistHashs = append(noExistHashs, hashNodes1[i].Hashs...)
}
}
for i, node := range nodes2 {
if i >= 5 {
existHashs = append(existHashs, node.hash)
existHashs = append(existHashs, hashNodes1[i].Hashs...)
} else if i == 2 {
for _, r := range records { } else {
updated := tree.Set([]byte(r.key), []byte(r.value)) noExistHashs = append(noExistHashs, node.hash)
if updated { noExistHashs = append(noExistHashs, hashNodes1[i].Hashs...)
t.Error("should have not been updated")
} }
} }
hash := tree.Save() verifyNodeExist(t, db2, existHashs, noExistHashs)
tree1 := NewTree(db, true) //检查转换成二级裁剪高度的节点
tree1.Load(hash) var secLevelNodes []*Node
records1 := []record{ secLevelNodes = append(secLevelNodes, &nodes1[2])
{"abc", "abc1"}, secLevelNodes = append(secLevelNodes, &nodes2[2])
{"low", "low1"}, VerifySecLevelCountNodeExist(t, db2, secLevelNodes)
{"fan", "fan1"}, }
{"foo", "foo1"},
//新增 func verifyNodeExist(t *testing.T, dbm db.DB, existHashs [][]byte, noExistHashs [][]byte) {
{"foobang", "foobang"}, for _, hash := range existHashs {
{"foobar", "foobar"}, _, err := dbm.Get(hash)
{"food", "food"}, if err != nil {
{"foml", "foml"}, require.NoError(t, fmt.Errorf("this node should exist %s", string(hash)))
}
}
for _, hash := range noExistHashs {
v, err := dbm.Get(hash)
if err == nil || len(v) > 0 {
require.NoError(t, fmt.Errorf("this node should not exist %s", string(hash)))
}
}
}
func VerifySecLevelCountNodeExist(t *testing.T, dbm db.DB, nodes []*Node) {
for _, node := range nodes {
_, err := dbm.Get(genOldLeafCountKey(node.key, node.hash, int64(node.height), len(node.hash)))
if err != nil {
require.NoError(t, fmt.Errorf("this node should exist key: %s, hash: %s", string(node.key), string(node.hash)))
}
} }
for _, r := range records1 { }
tree1.Set([]byte(r.key), []byte(r.value))
} func TestPruningSecondLevelNode(t *testing.T) {
hash1 := tree1.Save() dir, err := ioutil.TempDir("", "datastore")
//加入前缀的叶子节点
keyLeafs := []record{
{"abc", "0x5f6d625f2d303030303030303030302dd95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44d"},
{"low", "0x5f6d625f2d303030303030303030302d5a82d9685c0627c94ac5ba13e819c60e05b577bf6512062cf3dc2b5d9b381786"},
{"fan", "0x5f6d625f2d303030303030303030302d3bf26d01cb0752bcfd60b72348a8fde671f32f51ec276606cd5f35658c172114"},
{"foo", "0x5f6d625f2d303030303030303030302d890d4f4450d5ea213b8e63aae98fae548f210b5c8d3486b685cfa86adde16ec2"},
{"foml", "0x5f6d625f2d303030303030303030302d0ac69b0f4ceee514d09f2816e387cda870c06be28b50bf416de5c0ba90cdfbc0"},
{"foobang", "0x5f6d625f2d303030303030303030302d6d46d71882171840bcb61f2b60b69c904a4c30435bf03e63f4ec36bfa47ab2be"},
{"foobar", "0x5f6d625f2d303030303030303030302d5308d1f9b60e831a5df663babbf2a2636ecaf4da3bffed52447faf5ab172cf93"},
{"foobaz", "0x5f6d625f2d303030303030303030302dcbcb48848f0ce209cfccdf3ddf80740915c9bdede3cb11d0378690ad8b85a68b"},
{"food", "0x5f6d625f2d303030303030303030302de5080908c794168285a090088ae892793d549f3e7069f4feae3677bf3a28ad39"},
{"good", "0x5f6d625f2d303030303030303030302d0c99238587914476198da04cbb1555d092f813eaf2e796893084406290188776"},
}
//删除
delLeafs := []record{
{keyLeafs[0].key, keyLeafs[0].value},
{keyLeafs[1].key, keyLeafs[1].value},
{keyLeafs[2].key, keyLeafs[2].value},
{keyLeafs[3].key, keyLeafs[3].value},
}
mpleafHash := make(map[string]bool)
for _, d := range delLeafs {
k, _ := FromHex(d.value)
mpleafHash[string(k)] = true
}
pruningHashNode(db, mpleafHash)
tree2 := NewTree(db, true)
err = tree2.Load(hash1)
require.NoError(t, err) require.NoError(t, err)
upRecords := []record{ t.Log(dir)
{"abc", "abc1"}, defer os.RemoveAll(dir)
{"low", "low1"},
{"fan", "fan1"},
{"foo", "foo1"},
{"foobaz", "foobaz"},
{"good", "good"},
{"foobang", "foobang"}, db1 := db.NewDB("mavltree", "leveldb", dir, 100)
{"foobar", "foobar"}, //add node data
{"food", "food"}, nodes1 := []Node{
{"foml", "foml"}, {key: []byte("11111111"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44d"), height: 1},
{key: []byte("11111111"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44a"), height: 5000},
{key: []byte("11111111"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44b"), height: 10000},
} }
for _, k := range upRecords {
_, v, _ := tree2.Get([]byte(k.key)) nodes2 := []Node{
assert.Equal(t, []byte(k.value), v) {key: []byte("22222222"), hash: []byte("d95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc45d"), height: 1},
}
hashNodes1 := []types.PruneData{
{Hashs: [][]byte{[]byte("113"), []byte("114"), []byte("115"), []byte("116"), []byte("117"), []byte("118")}},
{Hashs: [][]byte{[]byte("123"), []byte("124"), []byte("125"), []byte("126"), []byte("127"), []byte("128")}},
{Hashs: [][]byte{[]byte("133"), []byte("134"), []byte("135"), []byte("136"), []byte("137"), []byte("138")}},
}
hashNodes2 := []types.PruneData{
{Hashs: [][]byte{[]byte("213"), []byte("214"), []byte("215"), []byte("216"), []byte("217"), []byte("218")}},
} }
batch := db1.NewBatch(true)
for i, node := range nodes1 {
k := genOldLeafCountKey(node.key, node.hash, int64(node.height), len(node.hash))
data := &types.PruneData{
Hashs: hashNodes1[i].Hashs,
}
v, err := proto.Marshal(data)
if err != nil {
panic(err)
}
// 保存索引节点
batch.Set(k, v)
// 保存叶子节点
batch.Set(node.hash, node.key)
// 保存hash节点
for _, hash := range data.Hashs {
batch.Set(hash, hash)
}
}
for i, node := range nodes2 {
k := genOldLeafCountKey(node.key, node.hash, int64(node.height), len(node.hash))
data := &types.PruneData{
Hashs: hashNodes2[i].Hashs,
}
v, err := proto.Marshal(data)
if err != nil {
panic(err)
}
// 保存索引节点
batch.Set(k, v)
// 保存叶子节点
batch.Set(node.hash, node.key)
// 保存hash节点
for _, hash := range data.Hashs {
batch.Set(hash, hash)
}
}
batch.Write()
db1.Close()
SetPruneHeight(5000)
db2 := db.NewDB("mavltree", "leveldb", dir, 100)
var existHashs [][]byte
var noExistHashs [][]byte
//当前高度设置为1500010,只能删除高度为1的节点
pruningSecondLevel(db2, 1500010)
for i, node := range nodes1 {
if i >= 2 {
existHashs = append(existHashs, node.hash)
existHashs = append(existHashs, hashNodes1[i].Hashs...)
} else {
noExistHashs = append(noExistHashs, node.hash)
noExistHashs = append(noExistHashs, hashNodes1[i].Hashs...)
}
}
verifyNodeExist(t, db2, existHashs, noExistHashs)
//检查转换成二级裁剪高度的节点
var secLevelNodes []*Node
secLevelNodes = append(secLevelNodes, &nodes2[0])
VerifyThreeLevelCountNodeExist(t, db2, secLevelNodes)
}
func VerifyThreeLevelCountNodeExist(t *testing.T, dbm db.DB, nodes []*Node) {
for _, node := range nodes {
v, err := dbm.Get(genOldLeafCountKey(node.key, node.hash, int64(node.height), len(node.hash)))
if err == nil || len(v) > 0 {
require.NoError(t, fmt.Errorf("this node should not exist key:%s hash:%s", string(node.key), string(node.hash)))
}
}
}
func TestGetHashNode(t *testing.T) {
eHashs := [][]byte{
[]byte("h44"),
[]byte("h33"),
[]byte("h22"),
[]byte("h11"),
[]byte("h00"),
}
root := &Node{
key: []byte("00"),
hash: []byte("h00"),
parentNode: nil,
}
node1 := &Node{
key: []byte("11"),
hash: []byte("h11"),
parentNode: root,
}
node2 := &Node{
key: []byte("22"),
hash: []byte("h22"),
parentNode: node1,
}
node3 := &Node{
key: []byte("33"),
hash: []byte("h33"),
parentNode: node2,
}
node4 := &Node{
key: []byte("44"),
hash: []byte("h44"),
parentNode: node3,
}
leafN := &Node{
key: []byte("55"),
hash: []byte("h55"),
parentNode: node4,
}
hashs := getHashNode(leafN)
require.Equal(t, len(eHashs), len(hashs))
for _, hash := range hashs {
t.Log("hash is ", string(hash))
require.Contains(t, eHashs, hash)
}
}
func TestGetKeyHeightFromLeafCountKey(t *testing.T) {
key := []byte("123456")
hash, err := FromHex("0x5f6d625f2d303030303030303030302dd95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44d")
require.NoError(t, err)
height := 100001
hashLen := len(hash)
hashkey := genLeafCountKey(key, hash, int64(height), hashLen)
//1
key1, height1, hash1, err := getKeyHeightFromLeafCountKey(hashkey)
require.NoError(t, err)
require.Equal(t, key, key1)
require.Equal(t, height, height1)
require.Equal(t, hash, hash1)
//2
key = []byte("24525252626988973653")
hash, err = FromHex("0xd95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44d")
require.NoError(t, err)
height = 453
hashLen = len(hash)
hashkey = genLeafCountKey(key, hash, int64(height), hashLen)
key1, height1, hash1, err = getKeyHeightFromLeafCountKey(hashkey)
require.NoError(t, err)
require.Equal(t, key, key1)
require.Equal(t, height, height1)
require.Equal(t, hash, hash1)
}
func TestGetKeyHeightFromOldLeafCountKey(t *testing.T) {
key := []byte("123456")
hash, err := FromHex("0x5f6d625f2d303030303030303030302dd95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44d")
require.NoError(t, err)
height := 100001
hashLen := len(hash)
hashkey := genOldLeafCountKey(key, hash, int64(height), hashLen)
//1
key1, height1, hash1, err := getKeyHeightFromOldLeafCountKey(hashkey)
require.NoError(t, err)
require.Equal(t, key, key1)
require.Equal(t, height, height1)
require.Equal(t, hash, hash1)
//2
key = []byte("24525252626988973653")
hash, err = FromHex("0xd95f1027b1ecf9013a1cf870a85d967ca828e8faca366a290ec43adcecfbc44d")
require.NoError(t, err)
height = 453
hashLen = len(hash)
hashkey = genOldLeafCountKey(key, hash, int64(height), hashLen)
key1, height1, hash1, err = getKeyHeightFromOldLeafCountKey(hashkey)
require.NoError(t, err)
require.Equal(t, key, key1)
require.Equal(t, height, height1)
require.Equal(t, hash, hash1)
} }
func BenchmarkDBSet(b *testing.B) { func BenchmarkDBSet(b *testing.B) {
......
...@@ -634,6 +634,7 @@ type ReqRandHash struct { ...@@ -634,6 +634,7 @@ type ReqRandHash struct {
ExecName string `protobuf:"bytes,1,opt,name=execName,proto3" json:"execName,omitempty"` ExecName string `protobuf:"bytes,1,opt,name=execName,proto3" json:"execName,omitempty"`
Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"`
BlockNum int64 `protobuf:"varint,3,opt,name=blockNum,proto3" json:"blockNum,omitempty"` BlockNum int64 `protobuf:"varint,3,opt,name=blockNum,proto3" json:"blockNum,omitempty"`
Hash []byte `protobuf:"bytes,4,opt,name=hash,proto3" json:"hash,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -685,6 +686,13 @@ func (m *ReqRandHash) GetBlockNum() int64 { ...@@ -685,6 +686,13 @@ func (m *ReqRandHash) GetBlockNum() int64 {
return 0 return 0
} }
func (m *ReqRandHash) GetHash() []byte {
if m != nil {
return m.Hash
}
return nil
}
//* //*
//当前软件版本信息 //当前软件版本信息
type VersionInfo struct { type VersionInfo struct {
...@@ -773,33 +781,33 @@ func init() { ...@@ -773,33 +781,33 @@ func init() {
func init() { proto.RegisterFile("common.proto", fileDescriptor_555bd8c177793206) } func init() { proto.RegisterFile("common.proto", fileDescriptor_555bd8c177793206) }
var fileDescriptor_555bd8c177793206 = []byte{ var fileDescriptor_555bd8c177793206 = []byte{
// 441 bytes of a gzipped FileDescriptorProto // 445 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x53, 0x5d, 0x6b, 0xdb, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x53, 0x51, 0x6b, 0xdb, 0x30,
0x14, 0x25, 0x71, 0x93, 0xc6, 0xb7, 0x7e, 0x18, 0x66, 0x0c, 0xd3, 0xb5, 0x34, 0xd3, 0x36, 0xc8, 0x10, 0x26, 0x71, 0x93, 0xc6, 0x57, 0x3f, 0x0c, 0x33, 0x86, 0xe9, 0x5a, 0x9a, 0x69, 0x1b, 0xe4,
0xcb, 0x1a, 0x98, 0xc7, 0x7e, 0xc0, 0xd8, 0xc3, 0x42, 0x21, 0x03, 0xb5, 0x94, 0x31, 0xd8, 0x83, 0x65, 0x0d, 0xcc, 0x63, 0x3f, 0x60, 0xec, 0x61, 0xa1, 0x90, 0x81, 0x5a, 0xca, 0xd8, 0x9b, 0xe2,
0xe2, 0xca, 0xb1, 0x88, 0x2c, 0x39, 0x91, 0x3c, 0xea, 0x7f, 0x3f, 0xee, 0xb5, 0x92, 0x65, 0x94, 0xca, 0xb1, 0x88, 0x2c, 0xd9, 0x91, 0x32, 0xea, 0x7f, 0x3f, 0xee, 0xa2, 0x64, 0x1e, 0x65, 0xeb,
0x6d, 0x6f, 0xf7, 0xe8, 0xdc, 0x8f, 0x73, 0x8e, 0x31, 0x24, 0x85, 0xad, 0x6b, 0x6b, 0xae, 0x9b, 0xdb, 0xf7, 0xe9, 0xee, 0xf4, 0x7d, 0xf7, 0x09, 0x41, 0x52, 0xd8, 0xba, 0xb6, 0xe6, 0xba, 0xd9,
0x9d, 0xf5, 0x36, 0x1d, 0xf9, 0xae, 0x91, 0x8e, 0xbd, 0x83, 0x11, 0x97, 0x8d, 0xee, 0xd2, 0x14, 0x5a, 0x6f, 0xd3, 0x91, 0xef, 0x1a, 0xe9, 0xd8, 0x07, 0x18, 0x71, 0xd9, 0xe8, 0x2e, 0x4d, 0xe1,
0x4e, 0x94, 0xfb, 0xba, 0xc9, 0x06, 0xd3, 0xc1, 0x6c, 0xc2, 0xa9, 0x4e, 0x9f, 0x41, 0x54, 0xbb, 0x44, 0xb9, 0xef, 0x9b, 0x6c, 0x30, 0x1d, 0xcc, 0x26, 0x9c, 0x70, 0xfa, 0x02, 0xa2, 0xda, 0xad,
0x75, 0x36, 0x9c, 0x0e, 0x66, 0x09, 0xc7, 0x92, 0x5d, 0x41, 0xcc, 0xe5, 0xf6, 0xd6, 0xef, 0x94, 0xb3, 0xe1, 0x74, 0x30, 0x4b, 0x38, 0x42, 0x76, 0x05, 0x31, 0x97, 0xed, 0xad, 0xdf, 0x2a, 0xb3,
0x59, 0xe3, 0xc8, 0x83, 0xf0, 0x82, 0x46, 0x62, 0x4e, 0x35, 0x7b, 0x05, 0x67, 0xb4, 0xef, 0x1f, 0xc6, 0x91, 0x07, 0xe1, 0x05, 0x8d, 0xc4, 0x9c, 0x30, 0x7b, 0x03, 0x67, 0x74, 0xdf, 0x7f, 0x5a,
0x2d, 0x6f, 0x20, 0x39, 0x6a, 0x71, 0xe9, 0x73, 0x18, 0xe1, 0xbb, 0xcb, 0x06, 0xd3, 0x68, 0x16, 0xde, 0x41, 0xd2, 0x6b, 0x71, 0xe9, 0x4b, 0x18, 0xe1, 0xb9, 0xcb, 0x06, 0xd3, 0x68, 0x16, 0xf3,
0xf3, 0x1e, 0xb0, 0x29, 0x8c, 0xb9, 0xdc, 0x2e, 0x8c, 0x4f, 0x5f, 0xc0, 0xb8, 0x92, 0x6a, 0x5d, 0x3d, 0x61, 0x53, 0x18, 0x73, 0xd9, 0x2e, 0x8c, 0x4f, 0x5f, 0xc1, 0xb8, 0x92, 0x6a, 0x5d, 0x79,
0x79, 0xda, 0x12, 0xf1, 0x80, 0xd8, 0x4b, 0x18, 0x2d, 0x8c, 0xff, 0xf8, 0xe1, 0x8f, 0x23, 0x51, 0xba, 0x25, 0xe2, 0x81, 0xb1, 0xd7, 0x30, 0x5a, 0x18, 0xff, 0xf9, 0xd3, 0x5f, 0x22, 0x51, 0x10,
0x38, 0x72, 0x09, 0xa7, 0x5c, 0x6e, 0xbf, 0x08, 0x57, 0x21, 0x5d, 0x09, 0x57, 0x11, 0x9d, 0x70, 0xb9, 0x84, 0x53, 0x2e, 0xdb, 0x6f, 0xc2, 0x55, 0x58, 0xae, 0x84, 0xab, 0xa8, 0x9c, 0x70, 0xc2,
0xaa, 0x7b, 0x1f, 0x8d, 0xee, 0xfe, 0xda, 0x30, 0xa1, 0xf3, 0x4b, 0xa5, 0xd9, 0x6b, 0xb2, 0x8c, 0xfb, 0x3d, 0x1a, 0xdd, 0xfd, 0xb3, 0x61, 0x42, 0xf2, 0x4b, 0xa5, 0xd9, 0x5b, 0x5a, 0x19, 0x1b,
0x8d, 0xd2, 0x91, 0x16, 0xaa, 0x48, 0x6c, 0xc2, 0x03, 0x62, 0x6f, 0x83, 0xed, 0xff, 0xb4, 0xbd, 0xa5, 0x23, 0x2f, 0x84, 0xc8, 0x6c, 0xc2, 0x03, 0x63, 0xef, 0xc3, 0xda, 0xcf, 0xb4, 0x7d, 0x84,
0x87, 0xc9, 0x8d, 0xec, 0xee, 0x85, 0x6e, 0x25, 0x86, 0xbb, 0x91, 0x5d, 0x38, 0x8a, 0x25, 0x06, 0xc9, 0x8d, 0xec, 0xee, 0x85, 0xde, 0x49, 0x0c, 0x77, 0x23, 0xbb, 0x20, 0x8a, 0x10, 0x83, 0xf8,
0xf1, 0x13, 0xa9, 0x10, 0x78, 0x0f, 0xd8, 0x05, 0x8c, 0xef, 0x1e, 0x9f, 0xe8, 0x8c, 0x83, 0xce, 0x85, 0xa5, 0x10, 0xf8, 0x9e, 0xb0, 0x0b, 0x18, 0xdf, 0x3d, 0x3e, 0xf1, 0x19, 0x07, 0x9f, 0x3f,
0x6f, 0x00, 0x77, 0xaa, 0x96, 0xb7, 0x5e, 0xf8, 0xd6, 0xa5, 0x19, 0x9c, 0x1a, 0xdf, 0xe0, 0x43, 0x00, 0xee, 0x54, 0x2d, 0x6f, 0xbd, 0xf0, 0x3b, 0x97, 0x66, 0x70, 0x6a, 0x7c, 0x83, 0x07, 0xa1,
0x68, 0xda, 0xc3, 0xf4, 0x02, 0x62, 0x6d, 0x0b, 0xa1, 0x89, 0x1b, 0x12, 0xf7, 0xfb, 0x81, 0x12, 0xe9, 0x40, 0xd3, 0x0b, 0x88, 0xb5, 0x2d, 0x84, 0xa6, 0xda, 0x90, 0x6a, 0x7f, 0x0e, 0x28, 0x41,
0x54, 0x65, 0x99, 0x45, 0x21, 0x41, 0x55, 0x96, 0xec, 0x9c, 0x12, 0xb8, 0x91, 0xdd, 0x53, 0xa5, 0x55, 0x96, 0x59, 0x14, 0x12, 0x54, 0x65, 0xc9, 0xce, 0x29, 0x81, 0x1b, 0xd9, 0x3d, 0x75, 0xca,
0xec, 0x07, 0xda, 0xdd, 0x72, 0x61, 0x1e, 0x48, 0xd8, 0x39, 0x4c, 0xe4, 0xa3, 0x2c, 0x96, 0xe2, 0x5a, 0x5c, 0xb7, 0xe5, 0xc2, 0x3c, 0x90, 0xb1, 0x73, 0x98, 0xc8, 0x47, 0x59, 0x2c, 0xc5, 0x51,
0x70, 0xf7, 0x80, 0x8f, 0xbe, 0xde, 0xf0, 0xf8, 0xeb, 0xe1, 0xcc, 0x4a, 0xdb, 0x62, 0xb3, 0x6c, 0xf7, 0xc8, 0x7b, 0xaf, 0x37, 0xec, 0xbf, 0x1e, 0xce, 0xac, 0xb4, 0x2d, 0x36, 0xcb, 0x5d, 0x1d,
0xeb, 0x70, 0xf6, 0x80, 0x99, 0x82, 0xb3, 0x7b, 0xb9, 0x73, 0xca, 0x9a, 0x85, 0x29, 0x2d, 0xe6, 0x64, 0x8f, 0xfc, 0xb8, 0xe8, 0x49, 0xef, 0x41, 0x14, 0x9c, 0xdd, 0xcb, 0xad, 0x53, 0xd6, 0x2c,
0xe2, 0x95, 0xd7, 0xfb, 0xdd, 0x3d, 0x40, 0x55, 0xa2, 0x69, 0x82, 0x17, 0x2c, 0xd1, 0x7d, 0x51, 0x4c, 0x69, 0x31, 0x2b, 0xaf, 0xbc, 0x3e, 0xe8, 0xed, 0x09, 0x3a, 0x15, 0x4d, 0x13, 0xf6, 0x43,
0x09, 0x65, 0xf2, 0x9c, 0x36, 0xc6, 0x7c, 0x0f, 0x91, 0x21, 0xb3, 0x9f, 0x57, 0xd9, 0x49, 0xcf, 0x88, 0x89, 0x14, 0x95, 0x50, 0x26, 0xcf, 0x49, 0x25, 0xe6, 0x07, 0x8a, 0x15, 0x0a, 0xe0, 0xeb,
0x04, 0xf8, 0xe9, 0xea, 0xfb, 0xe5, 0x5a, 0xf9, 0xaa, 0x5d, 0x5d, 0x17, 0xb6, 0x9e, 0xe7, 0x79, 0x8a, 0x74, 0x62, 0x7e, 0xa0, 0x5f, 0xae, 0x7e, 0x5e, 0xae, 0x95, 0xaf, 0x76, 0xab, 0xeb, 0xc2,
0x61, 0xe6, 0x61, 0x68, 0x4e, 0x3f, 0xc8, 0x6a, 0x4c, 0xbf, 0x4b, 0xfe, 0x2b, 0x00, 0x00, 0xff, 0xd6, 0xf3, 0x3c, 0x2f, 0xcc, 0x3c, 0x0c, 0xcd, 0xe9, 0xd3, 0xac, 0xc6, 0xf4, 0x85, 0xf2, 0xdf,
0xff, 0xed, 0x88, 0x46, 0x30, 0x3e, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0xff, 0x2c, 0x62, 0x19, 0x6f, 0x52, 0x03, 0x00, 0x00,
} }
...@@ -210,7 +210,6 @@ type StoreNode struct { ...@@ -210,7 +210,6 @@ type StoreNode struct {
RightHash []byte `protobuf:"bytes,4,opt,name=rightHash,proto3" json:"rightHash,omitempty"` RightHash []byte `protobuf:"bytes,4,opt,name=rightHash,proto3" json:"rightHash,omitempty"`
Height int32 `protobuf:"varint,5,opt,name=height,proto3" json:"height,omitempty"` Height int32 `protobuf:"varint,5,opt,name=height,proto3" json:"height,omitempty"`
Size int32 `protobuf:"varint,6,opt,name=size,proto3" json:"size,omitempty"` Size int32 `protobuf:"varint,6,opt,name=size,proto3" json:"size,omitempty"`
ParentHash []byte `protobuf:"bytes,7,opt,name=parentHash,proto3" json:"parentHash,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -283,13 +282,6 @@ func (m *StoreNode) GetSize() int32 { ...@@ -283,13 +282,6 @@ func (m *StoreNode) GetSize() int32 {
return 0 return 0
} }
func (m *StoreNode) GetParentHash() []byte {
if m != nil {
return m.ParentHash
}
return nil
}
type LocalDBSet struct { type LocalDBSet struct {
KV []*KeyValue `protobuf:"bytes,2,rep,name=KV,proto3" json:"KV,omitempty"` KV []*KeyValue `protobuf:"bytes,2,rep,name=KV,proto3" json:"KV,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
...@@ -888,10 +880,8 @@ func (m *StoreListReply) GetValues() [][]byte { ...@@ -888,10 +880,8 @@ func (m *StoreListReply) GetValues() [][]byte {
} }
type PruneData struct { type PruneData struct {
// 对应keyHash下的区块高度 // 该叶子节点的所有父hash
Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` Hashs [][]byte `protobuf:"bytes,1,rep,name=hashs,proto3" json:"hashs,omitempty"`
// hash+prefix的长度
Lenth int32 `protobuf:"varint,2,opt,name=lenth,proto3" json:"lenth,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -922,18 +912,11 @@ func (m *PruneData) XXX_DiscardUnknown() { ...@@ -922,18 +912,11 @@ func (m *PruneData) XXX_DiscardUnknown() {
var xxx_messageInfo_PruneData proto.InternalMessageInfo var xxx_messageInfo_PruneData proto.InternalMessageInfo
func (m *PruneData) GetHeight() int64 { func (m *PruneData) GetHashs() [][]byte {
if m != nil { if m != nil {
return m.Height return m.Hashs
} }
return 0 return nil
}
func (m *PruneData) GetLenth() int32 {
if m != nil {
return m.Lenth
}
return 0
} }
//用于存储db Pool数据的Value //用于存储db Pool数据的Value
...@@ -999,46 +982,45 @@ func init() { ...@@ -999,46 +982,45 @@ func init() {
func init() { proto.RegisterFile("db.proto", fileDescriptor_8817812184a13374) } func init() { proto.RegisterFile("db.proto", fileDescriptor_8817812184a13374) }
var fileDescriptor_8817812184a13374 = []byte{ var fileDescriptor_8817812184a13374 = []byte{
// 647 bytes of a gzipped FileDescriptorProto // 625 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0xdd, 0x6a, 0xdb, 0x4c, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0x4d, 0x6b, 0xdb, 0x40,
0x10, 0x45, 0x92, 0x95, 0x48, 0x93, 0xf0, 0xc5, 0x88, 0xf0, 0x61, 0x42, 0xda, 0x18, 0x5d, 0xb9, 0x10, 0x45, 0x92, 0x9d, 0x48, 0x93, 0xd0, 0x18, 0x11, 0x8a, 0x08, 0x29, 0x71, 0x75, 0x72, 0x29,
0x94, 0x3a, 0xa5, 0xbe, 0x2a, 0xf4, 0xa2, 0x0d, 0x81, 0xb4, 0xd8, 0x2d, 0x41, 0x06, 0x17, 0x7a, 0x75, 0x4a, 0x7d, 0xed, 0xa1, 0x0d, 0x81, 0xb4, 0xd8, 0x2d, 0x41, 0x06, 0x17, 0x7a, 0x28, 0x28,
0x51, 0xd8, 0xc8, 0xe3, 0x58, 0x44, 0xde, 0x75, 0xa5, 0x55, 0x89, 0xfa, 0x1a, 0x7d, 0x9a, 0xbe, 0xf2, 0x38, 0x12, 0xb1, 0x77, 0x5d, 0xed, 0xaa, 0x44, 0xfd, 0x1b, 0x3d, 0xf5, 0x6f, 0xf5, 0x17,
0x46, 0x9f, 0xa8, 0xec, 0xec, 0xea, 0x27, 0xc5, 0x89, 0x9b, 0xbb, 0x39, 0xe3, 0xf1, 0x9c, 0x33, 0x95, 0x9d, 0x5d, 0x7d, 0xa4, 0x38, 0x71, 0x73, 0xdb, 0x37, 0x1e, 0xcf, 0x7b, 0xf3, 0xe6, 0x81,
0x67, 0x67, 0x6c, 0xf0, 0xe6, 0x57, 0xc3, 0x75, 0x26, 0xa4, 0x08, 0x5c, 0x59, 0xae, 0x31, 0x3f, 0xc0, 0x9d, 0x5f, 0x0d, 0xd7, 0x39, 0x97, 0xdc, 0xef, 0xca, 0x72, 0x8d, 0xe2, 0x68, 0x3f, 0xe1,
0xda, 0x8f, 0xc5, 0x6a, 0x25, 0xb8, 0x4e, 0x86, 0x5f, 0xc1, 0x9b, 0x20, 0x5b, 0x7c, 0x12, 0x73, 0xab, 0x15, 0x67, 0xba, 0x18, 0x7e, 0x03, 0x77, 0x82, 0xf1, 0xe2, 0x33, 0x9f, 0xa3, 0xdf, 0x03,
0x0c, 0xba, 0xe0, 0xdc, 0x60, 0xd9, 0xb3, 0xfa, 0xd6, 0x60, 0x3f, 0x52, 0x61, 0x70, 0x08, 0xee, 0xe7, 0x06, 0xcb, 0xc0, 0xea, 0x5b, 0x83, 0xfd, 0x48, 0x3d, 0xfd, 0x43, 0xe8, 0xfe, 0x88, 0x97,
0x77, 0x96, 0x16, 0xd8, 0xb3, 0x29, 0xa7, 0x41, 0xf0, 0x3f, 0xec, 0x2c, 0x31, 0xb9, 0x5e, 0xca, 0x05, 0x06, 0x36, 0xd5, 0x34, 0xf0, 0x9f, 0xc2, 0x4e, 0x8a, 0xd9, 0x75, 0x2a, 0x03, 0xa7, 0x6f,
0x9e, 0xd3, 0xb7, 0x06, 0x6e, 0x64, 0x50, 0x10, 0x40, 0x27, 0x4f, 0x7e, 0x60, 0xaf, 0x43, 0x59, 0x0d, 0xba, 0x91, 0x41, 0xbe, 0x0f, 0x1d, 0x91, 0xfd, 0xc4, 0xa0, 0x43, 0x55, 0x7a, 0x87, 0xdf,
0x8a, 0xc3, 0x6f, 0xe0, 0x7f, 0xe0, 0x1c, 0x33, 0x22, 0x38, 0x02, 0x2f, 0xc5, 0x85, 0x7c, 0xcf, 0xc1, 0xfb, 0xc8, 0x18, 0xe6, 0x44, 0x70, 0x04, 0xee, 0x12, 0x17, 0xf2, 0x43, 0x2c, 0x52, 0xc3,
0xf2, 0xa5, 0x61, 0xa9, 0x71, 0x70, 0x0c, 0x7e, 0xa6, 0xba, 0xd0, 0x87, 0x9a, 0xae, 0x49, 0x3c, 0x52, 0x63, 0xff, 0x18, 0xbc, 0x5c, 0x4d, 0xa1, 0x1f, 0x35, 0x5d, 0x53, 0x78, 0x14, 0x65, 0x01,
0x8a, 0xb2, 0x00, 0xff, 0xe3, 0xbb, 0xd9, 0xe4, 0x32, 0x13, 0x62, 0xa1, 0x29, 0xd9, 0xe2, 0x2e, 0xde, 0xa7, 0xf7, 0xb3, 0xc9, 0x65, 0xce, 0xf9, 0x42, 0x53, 0xc6, 0x8b, 0xbb, 0x94, 0x1a, 0xfb,
0xa5, 0xc6, 0xc1, 0x4b, 0x80, 0xa4, 0xd2, 0x96, 0xf7, 0xec, 0xbe, 0x33, 0xd8, 0x7b, 0xd5, 0x1d, 0xaf, 0x01, 0xb2, 0x4a, 0x9b, 0x08, 0xec, 0xbe, 0x33, 0xd8, 0x7b, 0xd3, 0x1b, 0x92, 0x4b, 0xc3,
0x92, 0x4b, 0xc3, 0x5a, 0x74, 0xd4, 0xaa, 0x51, 0xdd, 0x32, 0x21, 0xb4, 0x46, 0x47, 0x77, 0xab, 0x5a, 0x74, 0xd4, 0xea, 0x51, 0xd3, 0x72, 0xce, 0xb5, 0x46, 0x47, 0x4f, 0xab, 0x70, 0xf8, 0xdb,
0x70, 0xf8, 0xcb, 0x02, 0x7f, 0x2a, 0x45, 0x86, 0x8f, 0xf2, 0xb2, 0x6d, 0x89, 0xf3, 0x90, 0x25, 0x02, 0x6f, 0x2a, 0x79, 0x8e, 0x8f, 0xf2, 0xb2, 0x6d, 0x89, 0xf3, 0x90, 0x25, 0x9d, 0xfb, 0x2d,
0x9d, 0xfb, 0x2d, 0x71, 0x37, 0x5a, 0xb2, 0xd3, 0x58, 0x12, 0x3c, 0x05, 0x58, 0xb3, 0x0c, 0xb9, 0xe9, 0x6e, 0xb4, 0x64, 0xa7, 0x65, 0xc9, 0x2b, 0x80, 0x09, 0x4f, 0xe2, 0xe5, 0xf9, 0xd9, 0x14,
0x6e, 0xb5, 0x4b, 0xad, 0x5a, 0x99, 0xf0, 0x05, 0xc0, 0x44, 0xc4, 0x2c, 0x3d, 0x3f, 0x9b, 0xa2, 0xa5, 0x7f, 0x02, 0xf6, 0x78, 0x66, 0xf6, 0x3d, 0x30, 0xfb, 0x8e, 0xb1, 0x9c, 0x29, 0x41, 0x91,
0x0c, 0x4e, 0xc0, 0x1e, 0xcf, 0x8c, 0x1f, 0x07, 0xc6, 0x8f, 0x31, 0x96, 0x33, 0x25, 0x38, 0xb2, 0x3d, 0x9e, 0x85, 0x37, 0xb0, 0x67, 0xda, 0x27, 0x99, 0x90, 0x8a, 0x69, 0x9d, 0xe3, 0x22, 0xbb,
0xc7, 0xb3, 0xf0, 0x06, 0xf6, 0x4c, 0xf9, 0x24, 0xc9, 0xa5, 0x52, 0xb2, 0xce, 0x70, 0x91, 0xdc, 0x35, 0xeb, 0x18, 0x54, 0xed, 0x68, 0x37, 0x3b, 0x1e, 0x83, 0x37, 0xcf, 0x72, 0x4c, 0x64, 0xc6,
0x9a, 0x71, 0x0d, 0xaa, 0x3c, 0xb0, 0x1b, 0x0f, 0x8e, 0xc1, 0x9f, 0x27, 0x19, 0xc6, 0x32, 0x11, 0x99, 0xb9, 0x54, 0x53, 0x50, 0x0e, 0x24, 0xbc, 0x60, 0xd2, 0x5c, 0x4b, 0x83, 0xb0, 0x5f, 0x6b,
0xdc, 0xbc, 0x64, 0x93, 0x50, 0x0e, 0xc5, 0xa2, 0xe0, 0xd2, 0xbc, 0xa6, 0x06, 0x61, 0xbf, 0xd6, 0xbb, 0x40, 0x52, 0x7f, 0x83, 0xa5, 0xbe, 0xc6, 0x7e, 0x44, 0xef, 0xf0, 0x05, 0x1c, 0x50, 0x47,
0x76, 0x81, 0x34, 0xdd, 0x0d, 0x96, 0xfa, 0xb5, 0xf6, 0x23, 0x8a, 0xc3, 0x67, 0x70, 0x40, 0x15, 0x84, 0xeb, 0xa5, 0x56, 0xa9, 0x24, 0x91, 0x7f, 0x55, 0xa3, 0x41, 0x61, 0x0c, 0x2e, 0xdd, 0x40,
0x11, 0xae, 0x53, 0xad, 0x52, 0x49, 0x22, 0x7f, 0xab, 0x42, 0x83, 0x42, 0x06, 0x1e, 0xbd, 0x91, 0xad, 0x79, 0x0c, 0x9e, 0x90, 0xb1, 0xc4, 0xd6, 0xed, 0x9b, 0xc2, 0x56, 0x13, 0xfe, 0x89, 0x9c,
0x1a, 0xf3, 0x18, 0xfc, 0x5c, 0x32, 0x89, 0xad, 0xdd, 0x68, 0x12, 0x5b, 0x4d, 0xf8, 0x6b, 0x25, 0x53, 0xf9, 0x1b, 0xbe, 0x33, 0x14, 0xe7, 0xb8, 0xdc, 0x42, 0xd1, 0x4c, 0xb0, 0xef, 0x4c, 0x98,
0x9d, 0xca, 0xff, 0xf0, 0xad, 0xa1, 0x38, 0xc7, 0x74, 0x0b, 0x45, 0xd3, 0xc1, 0xbe, 0xd3, 0x61, 0x42, 0xaf, 0x12, 0xf9, 0x25, 0x93, 0xe9, 0xb4, 0x64, 0x89, 0xff, 0x12, 0x5c, 0xa1, 0x6a, 0x02,
0x0a, 0xdd, 0x4a, 0xe4, 0xe7, 0x44, 0x2e, 0xa7, 0x25, 0x8f, 0x83, 0xe7, 0xe0, 0xe5, 0x2a, 0x97, 0x25, 0x0d, 0x6a, 0x44, 0x55, 0xad, 0x51, 0xdd, 0x40, 0x27, 0x2e, 0x59, 0x42, 0x63, 0xdd, 0x88,
0xa3, 0xa4, 0x46, 0x8d, 0xa8, 0xaa, 0x34, 0xaa, 0x0b, 0x68, 0x05, 0x4a, 0x1e, 0x53, 0x5b, 0x2f, 0xde, 0xe1, 0x5b, 0x23, 0xeb, 0x62, 0xeb, 0xe6, 0xf7, 0x58, 0x4c, 0xff, 0xfe, 0x0f, 0x8b, 0x7f,
0xa2, 0x38, 0x7c, 0x63, 0x64, 0x5d, 0x6c, 0x9d, 0xfc, 0x1e, 0x8b, 0xe9, 0xdb, 0xff, 0x60, 0xf1, 0x55, 0x39, 0xa7, 0x6c, 0x3c, 0x4c, 0x75, 0x08, 0x5d, 0x21, 0xe3, 0x5c, 0x56, 0x99, 0x27, 0xa0,
0xcf, 0xea, 0x0e, 0x68, 0x37, 0x1e, 0xa6, 0x3a, 0x04, 0x37, 0x97, 0x2c, 0x93, 0xd5, 0x4d, 0x10, 0x72, 0x83, 0x6c, 0x6e, 0xe2, 0xae, 0x9e, 0x8a, 0x4b, 0x14, 0x0b, 0x95, 0x30, 0x1d, 0x73, 0x83,
0x50, 0x7b, 0x83, 0x7c, 0x6e, 0xce, 0x41, 0x85, 0x8a, 0x2b, 0x2f, 0x16, 0x6a, 0xc3, 0xf4, 0x19, 0x9a, 0xc4, 0x74, 0xc9, 0x40, 0x0d, 0xd4, 0x02, 0x2b, 0x3e, 0xd7, 0x09, 0x77, 0x22, 0x7a, 0x87,
0x18, 0xd4, 0x6c, 0x8c, 0x4b, 0x06, 0x6a, 0xa0, 0x06, 0x58, 0x89, 0xb9, 0xbe, 0x00, 0x27, 0xa2, 0x7f, 0x2c, 0x78, 0x52, 0xab, 0xa2, 0x2d, 0x1a, 0x72, 0x6b, 0x03, 0xb9, 0xbd, 0x89, 0xdc, 0xd9,
0x38, 0xfc, 0x6d, 0xc1, 0x7f, 0xb5, 0x2a, 0x9a, 0xa2, 0x21, 0xb7, 0x36, 0x90, 0xdb, 0x9b, 0xc8, 0x4c, 0xde, 0x69, 0x93, 0xf7, 0xc0, 0x61, 0xc5, 0xca, 0x08, 0x52, 0xcf, 0x4d, 0x72, 0xfc, 0x00,
0x9d, 0xcd, 0xe4, 0x9d, 0x36, 0x79, 0x17, 0x1c, 0x5e, 0xac, 0x8c, 0x20, 0x15, 0x6e, 0x92, 0x13, 0x76, 0x19, 0xde, 0xca, 0x31, 0x96, 0xc1, 0x2e, 0x0d, 0xad, 0x60, 0xed, 0xbe, 0xdb, 0xb8, 0xdf,
0xf4, 0x60, 0x97, 0xe3, 0xad, 0x1c, 0x63, 0x69, 0xae, 0xb1, 0x82, 0xb5, 0xfb, 0x5e, 0xe3, 0x7e, 0xb2, 0xda, 0xbb, 0x63, 0xf5, 0x73, 0xf0, 0x2e, 0xf3, 0x82, 0xe1, 0x79, 0x2c, 0x63, 0x25, 0x27,
0xcb, 0x6a, 0xff, 0x8e, 0xd5, 0xaf, 0xc1, 0xbf, 0xcc, 0x0a, 0x8e, 0xe7, 0x4c, 0xb2, 0xd6, 0x36, 0x8d, 0x45, 0x2a, 0x02, 0x8b, 0x7a, 0x34, 0x08, 0x07, 0x66, 0x6d, 0xba, 0xd9, 0x25, 0xe7, 0xcb,
0x59, 0xed, 0x6d, 0x52, 0x32, 0x53, 0xe4, 0x52, 0xff, 0xa8, 0xba, 0x91, 0x06, 0xe1, 0xc0, 0xd8, 0xd6, 0x30, 0xab, 0x3d, 0xec, 0xec, 0xe4, 0xeb, 0xb3, 0xeb, 0x4c, 0xa6, 0xc5, 0xd5, 0x30, 0xe1,
0x41, 0x6f, 0x79, 0x29, 0x44, 0xda, 0x22, 0xb1, 0xda, 0x24, 0x67, 0x27, 0x5f, 0x9e, 0x5c, 0x27, 0xab, 0xd3, 0xd1, 0x28, 0x61, 0xa7, 0x49, 0x1a, 0x67, 0x6c, 0x34, 0x3a, 0xa5, 0xa0, 0x5d, 0xed,
0x72, 0x59, 0x5c, 0x0d, 0x63, 0xb1, 0x3a, 0x1d, 0x8d, 0x62, 0x7e, 0x1a, 0x2f, 0x59, 0xc2, 0x47, 0xd0, 0x17, 0x61, 0xf4, 0x37, 0x00, 0x00, 0xff, 0xff, 0xc1, 0x81, 0x98, 0x2a, 0x32, 0x06, 0x00,
0xa3, 0x53, 0x5a, 0xc0, 0xab, 0x1d, 0xfa, 0x27, 0x19, 0xfd, 0x09, 0x00, 0x00, 0xff, 0xff, 0x30, 0x00,
0x37, 0x20, 0x41, 0x6a, 0x06, 0x00, 0x00,
} }
...@@ -174,4 +174,8 @@ var ( ...@@ -174,4 +174,8 @@ var (
ErrCloneForkFrom = errors.New("ErrCloneForkFrom") ErrCloneForkFrom = errors.New("ErrCloneForkFrom")
ErrCloneForkToExist = errors.New("ErrCloneForkToExist") ErrCloneForkToExist = errors.New("ErrCloneForkToExist")
ErrQueryThistIsNotSet = errors.New("ErrQueryThistIsNotSet") ErrQueryThistIsNotSet = errors.New("ErrQueryThistIsNotSet")
ErrHeightLessZero = errors.New("ErrHeightLessZero")
ErrHeightOverflow = errors.New("ErrHeightOverflow")
ErrRecordBlockSequence = errors.New("ErrRecordBlockSequence")
) )
...@@ -161,9 +161,9 @@ message MsgWithRequired { ...@@ -161,9 +161,9 @@ message MsgWithRequired {
} }
message MsgWithIndirectRequired { message MsgWithIndirectRequired {
optional MsgWithRequired subm = 1; optional MsgWithRequired subm = 1;
map<string, MsgWithRequired> map_field = 2; map<string, MsgWithRequired> map_field = 2;
repeated MsgWithRequired slice_field = 3; repeated MsgWithRequired slice_field = 3;
} }
message MsgWithRequiredBytes { message MsgWithRequiredBytes {
......
...@@ -45,8 +45,8 @@ message Blocks { ...@@ -45,8 +45,8 @@ message Blocks {
} }
message BlockSeqCB { message BlockSeqCB {
string name = 1; string name = 1;
string URL = 2; string URL = 2;
string encode = 3; string encode = 3;
} }
...@@ -55,9 +55,9 @@ message BlockSeqCBs { ...@@ -55,9 +55,9 @@ message BlockSeqCBs {
} }
message BlockSeq { message BlockSeq {
int64 num = 1; int64 num = 1;
BlockSequence seq = 2; BlockSequence seq = 2;
BlockDetail detail = 3; BlockDetail detail = 3;
} }
//节点ID以及对应的Block //节点ID以及对应的Block
......
...@@ -66,17 +66,18 @@ message ReqKey { ...@@ -66,17 +66,18 @@ message ReqKey {
} }
message ReqRandHash { message ReqRandHash {
string execName = 1; string execName = 1;
int64 height = 2; int64 height = 2;
int64 blockNum = 3; int64 blockNum = 3;
bytes hash = 4;
} }
/** /**
*当前软件版本信息 *当前软件版本信息
*/ */
message VersionInfo { message VersionInfo {
string title = 1; string title = 1;
string app = 2; string app = 2;
string chain33 = 3; string chain33 = 3;
string localDb = 4; string localDb = 4;
} }
\ No newline at end of file
...@@ -27,13 +27,12 @@ message MAVLProof { ...@@ -27,13 +27,12 @@ message MAVLProof {
} }
message StoreNode { message StoreNode {
bytes key = 1; bytes key = 1;
bytes value = 2; bytes value = 2;
bytes leftHash = 3; bytes leftHash = 3;
bytes rightHash = 4; bytes rightHash = 4;
int32 height = 5; int32 height = 5;
int32 size = 6; int32 size = 6;
bytes parentHash = 7;
} }
message LocalDBSet { message LocalDBSet {
...@@ -102,12 +101,8 @@ message StoreListReply { ...@@ -102,12 +101,8 @@ message StoreListReply {
} }
message PruneData { message PruneData {
// 对应keyHash下的区块高度 // 该叶子节点的所有父hash
int64 height = 1; repeated bytes hashs = 1;
// hash+prefix的长度
int32 lenth = 2;
// 该叶子节点的roothash
// bytes rHash = 3;
} }
//用于存储db Pool数据的Value //用于存储db Pool数据的Value
......
...@@ -125,7 +125,7 @@ service chain33 { ...@@ -125,7 +125,7 @@ service chain33 {
//获取指定区间的block加载序列号信息 //获取指定区间的block加载序列号信息
rpc GetBlockSequences(ReqBlocks) returns (BlockSequences) {} rpc GetBlockSequences(ReqBlocks) returns (BlockSequences) {}
//get add block's sequence by hash // get add block's sequence by hash
rpc GetSequenceByHash(ReqHash) returns (Int64) {} rpc GetSequenceByHash(ReqHash) returns (Int64) {}
//通过block hash 获取对应的blocks信息 //通过block hash 获取对应的blocks信息
...@@ -139,7 +139,7 @@ service chain33 { ...@@ -139,7 +139,7 @@ service chain33 {
rpc SignRawTx(ReqSignRawTx) returns (ReplySignRawTx) {} rpc SignRawTx(ReqSignRawTx) returns (ReplySignRawTx) {}
rpc CreateNoBalanceTransaction(NoBalanceTx) returns (ReplySignRawTx) {} rpc CreateNoBalanceTransaction(NoBalanceTx) returns (ReplySignRawTx) {}
// 获取随机HASH // 获取随机HASH
rpc QueryRandNum(ReqRandHash) returns(ReplyHash) {} rpc QueryRandNum(ReqRandHash) returns (ReplyHash) {}
} }
...@@ -73,8 +73,8 @@ message ReqGetExecBalance { ...@@ -73,8 +73,8 @@ message ReqGetExecBalance {
bytes addr = 3; bytes addr = 3;
bytes execAddr = 4; bytes execAddr = 4;
string execer = 5; string execer = 5;
int64 count = 6; int64 count = 6;
bytes nextKey = 7; bytes nextKey = 7;
} }
message ExecBalanceItem { message ExecBalanceItem {
......
...@@ -52,6 +52,14 @@ message CreateTx { ...@@ -52,6 +52,14 @@ message CreateTx {
string execer = 9; string execer = 9;
} }
message ReWriteRawTx {
string tx = 1;
bytes execer = 2;
string to = 3;
string expire = 4;
int64 fee = 5;
}
message CreateTransactionGroup { message CreateTransactionGroup {
repeated string txs = 1; repeated string txs = 1;
} }
......
...@@ -204,7 +204,10 @@ message ReqSignRawTx { ...@@ -204,7 +204,10 @@ message ReqSignRawTx {
// 0:普通交易 // 0:普通交易
// 1:隐私交易 // 1:隐私交易
// int32 mode = 6; // int32 mode = 6;
string token = 7; string token = 7;
int64 fee = 8;
bytes newExecer = 9;
string newToAddr = 10;
} }
message ReplySignRawTx { message ReplySignRawTx {
...@@ -229,9 +232,9 @@ message ReqCreateTransaction { ...@@ -229,9 +232,9 @@ message ReqCreateTransaction {
// 1:隐私交易 公开->隐私 // 1:隐私交易 公开->隐私
// 2:隐私交易 隐私->隐私 // 2:隐私交易 隐私->隐私
// 3:隐私交易 隐私->公开 // 3:隐私交易 隐私->公开
int32 type = 2; int32 type = 2;
int64 amount = 3; int64 amount = 3;
bytes note = 4; bytes note = 4;
// 普通交易的发送方 // 普通交易的发送方
string from = 5; string from = 5;
// 普通交易的接收方 // 普通交易的接收方
......
...@@ -191,7 +191,7 @@ type Chain33Client interface { ...@@ -191,7 +191,7 @@ type Chain33Client interface {
GetLastBlockSequence(ctx context.Context, in *ReqNil, opts ...grpc.CallOption) (*Int64, error) GetLastBlockSequence(ctx context.Context, in *ReqNil, opts ...grpc.CallOption) (*Int64, error)
//获取指定区间的block加载序列号信息 //获取指定区间的block加载序列号信息
GetBlockSequences(ctx context.Context, in *ReqBlocks, opts ...grpc.CallOption) (*BlockSequences, error) GetBlockSequences(ctx context.Context, in *ReqBlocks, opts ...grpc.CallOption) (*BlockSequences, error)
//get add block's sequence by hash // get add block's sequence by hash
GetSequenceByHash(ctx context.Context, in *ReqHash, opts ...grpc.CallOption) (*Int64, error) GetSequenceByHash(ctx context.Context, in *ReqHash, opts ...grpc.CallOption) (*Int64, error)
//通过block hash 获取对应的blocks信息 //通过block hash 获取对应的blocks信息
GetBlockByHashes(ctx context.Context, in *ReqHashes, opts ...grpc.CallOption) (*BlockDetails, error) GetBlockByHashes(ctx context.Context, in *ReqHashes, opts ...grpc.CallOption) (*BlockDetails, error)
...@@ -760,7 +760,7 @@ type Chain33Server interface { ...@@ -760,7 +760,7 @@ type Chain33Server interface {
GetLastBlockSequence(context.Context, *ReqNil) (*Int64, error) GetLastBlockSequence(context.Context, *ReqNil) (*Int64, error)
//获取指定区间的block加载序列号信息 //获取指定区间的block加载序列号信息
GetBlockSequences(context.Context, *ReqBlocks) (*BlockSequences, error) GetBlockSequences(context.Context, *ReqBlocks) (*BlockSequences, error)
//get add block's sequence by hash // get add block's sequence by hash
GetSequenceByHash(context.Context, *ReqHash) (*Int64, error) GetSequenceByHash(context.Context, *ReqHash) (*Int64, error)
//通过block hash 获取对应的blocks信息 //通过block hash 获取对应的blocks信息
GetBlockByHashes(context.Context, *ReqHashes) (*BlockDetails, error) GetBlockByHashes(context.Context, *ReqHashes) (*BlockDetails, error)
......
...@@ -432,6 +432,77 @@ func (m *CreateTx) GetExecer() string { ...@@ -432,6 +432,77 @@ func (m *CreateTx) GetExecer() string {
return "" return ""
} }
type ReWriteRawTx struct {
Tx string `protobuf:"bytes,1,opt,name=tx,proto3" json:"tx,omitempty"`
Execer []byte `protobuf:"bytes,2,opt,name=execer,proto3" json:"execer,omitempty"`
To string `protobuf:"bytes,3,opt,name=to,proto3" json:"to,omitempty"`
Expire string `protobuf:"bytes,4,opt,name=expire,proto3" json:"expire,omitempty"`
Fee int64 `protobuf:"varint,5,opt,name=fee,proto3" json:"fee,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReWriteRawTx) Reset() { *m = ReWriteRawTx{} }
func (m *ReWriteRawTx) String() string { return proto.CompactTextString(m) }
func (*ReWriteRawTx) ProtoMessage() {}
func (*ReWriteRawTx) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{6}
}
func (m *ReWriteRawTx) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReWriteRawTx.Unmarshal(m, b)
}
func (m *ReWriteRawTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReWriteRawTx.Marshal(b, m, deterministic)
}
func (m *ReWriteRawTx) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReWriteRawTx.Merge(m, src)
}
func (m *ReWriteRawTx) XXX_Size() int {
return xxx_messageInfo_ReWriteRawTx.Size(m)
}
func (m *ReWriteRawTx) XXX_DiscardUnknown() {
xxx_messageInfo_ReWriteRawTx.DiscardUnknown(m)
}
var xxx_messageInfo_ReWriteRawTx proto.InternalMessageInfo
func (m *ReWriteRawTx) GetTx() string {
if m != nil {
return m.Tx
}
return ""
}
func (m *ReWriteRawTx) GetExecer() []byte {
if m != nil {
return m.Execer
}
return nil
}
func (m *ReWriteRawTx) GetTo() string {
if m != nil {
return m.To
}
return ""
}
func (m *ReWriteRawTx) GetExpire() string {
if m != nil {
return m.Expire
}
return ""
}
func (m *ReWriteRawTx) GetFee() int64 {
if m != nil {
return m.Fee
}
return 0
}
type CreateTransactionGroup struct { type CreateTransactionGroup struct {
Txs []string `protobuf:"bytes,1,rep,name=txs,proto3" json:"txs,omitempty"` Txs []string `protobuf:"bytes,1,rep,name=txs,proto3" json:"txs,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
...@@ -443,7 +514,7 @@ func (m *CreateTransactionGroup) Reset() { *m = CreateTransactionGroup{} ...@@ -443,7 +514,7 @@ func (m *CreateTransactionGroup) Reset() { *m = CreateTransactionGroup{}
func (m *CreateTransactionGroup) String() string { return proto.CompactTextString(m) } func (m *CreateTransactionGroup) String() string { return proto.CompactTextString(m) }
func (*CreateTransactionGroup) ProtoMessage() {} func (*CreateTransactionGroup) ProtoMessage() {}
func (*CreateTransactionGroup) Descriptor() ([]byte, []int) { func (*CreateTransactionGroup) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{6} return fileDescriptor_2cc4e03d2c28c490, []int{7}
} }
func (m *CreateTransactionGroup) XXX_Unmarshal(b []byte) error { func (m *CreateTransactionGroup) XXX_Unmarshal(b []byte) error {
...@@ -482,7 +553,7 @@ func (m *UnsignTx) Reset() { *m = UnsignTx{} } ...@@ -482,7 +553,7 @@ func (m *UnsignTx) Reset() { *m = UnsignTx{} }
func (m *UnsignTx) String() string { return proto.CompactTextString(m) } func (m *UnsignTx) String() string { return proto.CompactTextString(m) }
func (*UnsignTx) ProtoMessage() {} func (*UnsignTx) ProtoMessage() {}
func (*UnsignTx) Descriptor() ([]byte, []int) { func (*UnsignTx) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{7} return fileDescriptor_2cc4e03d2c28c490, []int{8}
} }
func (m *UnsignTx) XXX_Unmarshal(b []byte) error { func (m *UnsignTx) XXX_Unmarshal(b []byte) error {
...@@ -525,7 +596,7 @@ func (m *NoBalanceTx) Reset() { *m = NoBalanceTx{} } ...@@ -525,7 +596,7 @@ func (m *NoBalanceTx) Reset() { *m = NoBalanceTx{} }
func (m *NoBalanceTx) String() string { return proto.CompactTextString(m) } func (m *NoBalanceTx) String() string { return proto.CompactTextString(m) }
func (*NoBalanceTx) ProtoMessage() {} func (*NoBalanceTx) ProtoMessage() {}
func (*NoBalanceTx) Descriptor() ([]byte, []int) { func (*NoBalanceTx) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{8} return fileDescriptor_2cc4e03d2c28c490, []int{9}
} }
func (m *NoBalanceTx) XXX_Unmarshal(b []byte) error { func (m *NoBalanceTx) XXX_Unmarshal(b []byte) error {
...@@ -588,7 +659,7 @@ func (m *SignedTx) Reset() { *m = SignedTx{} } ...@@ -588,7 +659,7 @@ func (m *SignedTx) Reset() { *m = SignedTx{} }
func (m *SignedTx) String() string { return proto.CompactTextString(m) } func (m *SignedTx) String() string { return proto.CompactTextString(m) }
func (*SignedTx) ProtoMessage() {} func (*SignedTx) ProtoMessage() {}
func (*SignedTx) Descriptor() ([]byte, []int) { func (*SignedTx) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{9} return fileDescriptor_2cc4e03d2c28c490, []int{10}
} }
func (m *SignedTx) XXX_Unmarshal(b []byte) error { func (m *SignedTx) XXX_Unmarshal(b []byte) error {
...@@ -659,7 +730,7 @@ func (m *Transaction) Reset() { *m = Transaction{} } ...@@ -659,7 +730,7 @@ func (m *Transaction) Reset() { *m = Transaction{} }
func (m *Transaction) String() string { return proto.CompactTextString(m) } func (m *Transaction) String() string { return proto.CompactTextString(m) }
func (*Transaction) ProtoMessage() {} func (*Transaction) ProtoMessage() {}
func (*Transaction) Descriptor() ([]byte, []int) { func (*Transaction) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{10} return fileDescriptor_2cc4e03d2c28c490, []int{11}
} }
func (m *Transaction) XXX_Unmarshal(b []byte) error { func (m *Transaction) XXX_Unmarshal(b []byte) error {
...@@ -761,7 +832,7 @@ func (m *Transactions) Reset() { *m = Transactions{} } ...@@ -761,7 +832,7 @@ func (m *Transactions) Reset() { *m = Transactions{} }
func (m *Transactions) String() string { return proto.CompactTextString(m) } func (m *Transactions) String() string { return proto.CompactTextString(m) }
func (*Transactions) ProtoMessage() {} func (*Transactions) ProtoMessage() {}
func (*Transactions) Descriptor() ([]byte, []int) { func (*Transactions) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{11} return fileDescriptor_2cc4e03d2c28c490, []int{12}
} }
func (m *Transactions) XXX_Unmarshal(b []byte) error { func (m *Transactions) XXX_Unmarshal(b []byte) error {
...@@ -801,7 +872,7 @@ func (m *RingSignature) Reset() { *m = RingSignature{} } ...@@ -801,7 +872,7 @@ func (m *RingSignature) Reset() { *m = RingSignature{} }
func (m *RingSignature) String() string { return proto.CompactTextString(m) } func (m *RingSignature) String() string { return proto.CompactTextString(m) }
func (*RingSignature) ProtoMessage() {} func (*RingSignature) ProtoMessage() {}
func (*RingSignature) Descriptor() ([]byte, []int) { func (*RingSignature) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{12} return fileDescriptor_2cc4e03d2c28c490, []int{13}
} }
func (m *RingSignature) XXX_Unmarshal(b []byte) error { func (m *RingSignature) XXX_Unmarshal(b []byte) error {
...@@ -842,7 +913,7 @@ func (m *RingSignatureItem) Reset() { *m = RingSignatureItem{} } ...@@ -842,7 +913,7 @@ func (m *RingSignatureItem) Reset() { *m = RingSignatureItem{} }
func (m *RingSignatureItem) String() string { return proto.CompactTextString(m) } func (m *RingSignatureItem) String() string { return proto.CompactTextString(m) }
func (*RingSignatureItem) ProtoMessage() {} func (*RingSignatureItem) ProtoMessage() {}
func (*RingSignatureItem) Descriptor() ([]byte, []int) { func (*RingSignatureItem) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{13} return fileDescriptor_2cc4e03d2c28c490, []int{14}
} }
func (m *RingSignatureItem) XXX_Unmarshal(b []byte) error { func (m *RingSignatureItem) XXX_Unmarshal(b []byte) error {
...@@ -901,7 +972,7 @@ func (m *Signature) Reset() { *m = Signature{} } ...@@ -901,7 +972,7 @@ func (m *Signature) Reset() { *m = Signature{} }
func (m *Signature) String() string { return proto.CompactTextString(m) } func (m *Signature) String() string { return proto.CompactTextString(m) }
func (*Signature) ProtoMessage() {} func (*Signature) ProtoMessage() {}
func (*Signature) Descriptor() ([]byte, []int) { func (*Signature) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{14} return fileDescriptor_2cc4e03d2c28c490, []int{15}
} }
func (m *Signature) XXX_Unmarshal(b []byte) error { func (m *Signature) XXX_Unmarshal(b []byte) error {
...@@ -956,7 +1027,7 @@ func (m *AddrOverview) Reset() { *m = AddrOverview{} } ...@@ -956,7 +1027,7 @@ func (m *AddrOverview) Reset() { *m = AddrOverview{} }
func (m *AddrOverview) String() string { return proto.CompactTextString(m) } func (m *AddrOverview) String() string { return proto.CompactTextString(m) }
func (*AddrOverview) ProtoMessage() {} func (*AddrOverview) ProtoMessage() {}
func (*AddrOverview) Descriptor() ([]byte, []int) { func (*AddrOverview) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{15} return fileDescriptor_2cc4e03d2c28c490, []int{16}
} }
func (m *AddrOverview) XXX_Unmarshal(b []byte) error { func (m *AddrOverview) XXX_Unmarshal(b []byte) error {
...@@ -1015,7 +1086,7 @@ func (m *ReqAddr) Reset() { *m = ReqAddr{} } ...@@ -1015,7 +1086,7 @@ func (m *ReqAddr) Reset() { *m = ReqAddr{} }
func (m *ReqAddr) String() string { return proto.CompactTextString(m) } func (m *ReqAddr) String() string { return proto.CompactTextString(m) }
func (*ReqAddr) ProtoMessage() {} func (*ReqAddr) ProtoMessage() {}
func (*ReqAddr) Descriptor() ([]byte, []int) { func (*ReqAddr) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{16} return fileDescriptor_2cc4e03d2c28c490, []int{17}
} }
func (m *ReqAddr) XXX_Unmarshal(b []byte) error { func (m *ReqAddr) XXX_Unmarshal(b []byte) error {
...@@ -1091,7 +1162,7 @@ func (m *ReqPrivacy) Reset() { *m = ReqPrivacy{} } ...@@ -1091,7 +1162,7 @@ func (m *ReqPrivacy) Reset() { *m = ReqPrivacy{} }
func (m *ReqPrivacy) String() string { return proto.CompactTextString(m) } func (m *ReqPrivacy) String() string { return proto.CompactTextString(m) }
func (*ReqPrivacy) ProtoMessage() {} func (*ReqPrivacy) ProtoMessage() {}
func (*ReqPrivacy) Descriptor() ([]byte, []int) { func (*ReqPrivacy) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{17} return fileDescriptor_2cc4e03d2c28c490, []int{18}
} }
func (m *ReqPrivacy) XXX_Unmarshal(b []byte) error { func (m *ReqPrivacy) XXX_Unmarshal(b []byte) error {
...@@ -1144,7 +1215,7 @@ func (m *HexTx) Reset() { *m = HexTx{} } ...@@ -1144,7 +1215,7 @@ func (m *HexTx) Reset() { *m = HexTx{} }
func (m *HexTx) String() string { return proto.CompactTextString(m) } func (m *HexTx) String() string { return proto.CompactTextString(m) }
func (*HexTx) ProtoMessage() {} func (*HexTx) ProtoMessage() {}
func (*HexTx) Descriptor() ([]byte, []int) { func (*HexTx) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{18} return fileDescriptor_2cc4e03d2c28c490, []int{19}
} }
func (m *HexTx) XXX_Unmarshal(b []byte) error { func (m *HexTx) XXX_Unmarshal(b []byte) error {
...@@ -1186,7 +1257,7 @@ func (m *ReplyTxInfo) Reset() { *m = ReplyTxInfo{} } ...@@ -1186,7 +1257,7 @@ func (m *ReplyTxInfo) Reset() { *m = ReplyTxInfo{} }
func (m *ReplyTxInfo) String() string { return proto.CompactTextString(m) } func (m *ReplyTxInfo) String() string { return proto.CompactTextString(m) }
func (*ReplyTxInfo) ProtoMessage() {} func (*ReplyTxInfo) ProtoMessage() {}
func (*ReplyTxInfo) Descriptor() ([]byte, []int) { func (*ReplyTxInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{19} return fileDescriptor_2cc4e03d2c28c490, []int{20}
} }
func (m *ReplyTxInfo) XXX_Unmarshal(b []byte) error { func (m *ReplyTxInfo) XXX_Unmarshal(b []byte) error {
...@@ -1246,7 +1317,7 @@ func (m *ReqTxList) Reset() { *m = ReqTxList{} } ...@@ -1246,7 +1317,7 @@ func (m *ReqTxList) Reset() { *m = ReqTxList{} }
func (m *ReqTxList) String() string { return proto.CompactTextString(m) } func (m *ReqTxList) String() string { return proto.CompactTextString(m) }
func (*ReqTxList) ProtoMessage() {} func (*ReqTxList) ProtoMessage() {}
func (*ReqTxList) Descriptor() ([]byte, []int) { func (*ReqTxList) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{20} return fileDescriptor_2cc4e03d2c28c490, []int{21}
} }
func (m *ReqTxList) XXX_Unmarshal(b []byte) error { func (m *ReqTxList) XXX_Unmarshal(b []byte) error {
...@@ -1285,7 +1356,7 @@ func (m *ReplyTxList) Reset() { *m = ReplyTxList{} } ...@@ -1285,7 +1356,7 @@ func (m *ReplyTxList) Reset() { *m = ReplyTxList{} }
func (m *ReplyTxList) String() string { return proto.CompactTextString(m) } func (m *ReplyTxList) String() string { return proto.CompactTextString(m) }
func (*ReplyTxList) ProtoMessage() {} func (*ReplyTxList) ProtoMessage() {}
func (*ReplyTxList) Descriptor() ([]byte, []int) { func (*ReplyTxList) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{21} return fileDescriptor_2cc4e03d2c28c490, []int{22}
} }
func (m *ReplyTxList) XXX_Unmarshal(b []byte) error { func (m *ReplyTxList) XXX_Unmarshal(b []byte) error {
...@@ -1326,7 +1397,7 @@ func (m *TxHashList) Reset() { *m = TxHashList{} } ...@@ -1326,7 +1397,7 @@ func (m *TxHashList) Reset() { *m = TxHashList{} }
func (m *TxHashList) String() string { return proto.CompactTextString(m) } func (m *TxHashList) String() string { return proto.CompactTextString(m) }
func (*TxHashList) ProtoMessage() {} func (*TxHashList) ProtoMessage() {}
func (*TxHashList) Descriptor() ([]byte, []int) { func (*TxHashList) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{22} return fileDescriptor_2cc4e03d2c28c490, []int{23}
} }
func (m *TxHashList) XXX_Unmarshal(b []byte) error { func (m *TxHashList) XXX_Unmarshal(b []byte) error {
...@@ -1379,7 +1450,7 @@ func (m *ReplyTxInfos) Reset() { *m = ReplyTxInfos{} } ...@@ -1379,7 +1450,7 @@ func (m *ReplyTxInfos) Reset() { *m = ReplyTxInfos{} }
func (m *ReplyTxInfos) String() string { return proto.CompactTextString(m) } func (m *ReplyTxInfos) String() string { return proto.CompactTextString(m) }
func (*ReplyTxInfos) ProtoMessage() {} func (*ReplyTxInfos) ProtoMessage() {}
func (*ReplyTxInfos) Descriptor() ([]byte, []int) { func (*ReplyTxInfos) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{23} return fileDescriptor_2cc4e03d2c28c490, []int{24}
} }
func (m *ReplyTxInfos) XXX_Unmarshal(b []byte) error { func (m *ReplyTxInfos) XXX_Unmarshal(b []byte) error {
...@@ -1419,7 +1490,7 @@ func (m *ReceiptLog) Reset() { *m = ReceiptLog{} } ...@@ -1419,7 +1490,7 @@ func (m *ReceiptLog) Reset() { *m = ReceiptLog{} }
func (m *ReceiptLog) String() string { return proto.CompactTextString(m) } func (m *ReceiptLog) String() string { return proto.CompactTextString(m) }
func (*ReceiptLog) ProtoMessage() {} func (*ReceiptLog) ProtoMessage() {}
func (*ReceiptLog) Descriptor() ([]byte, []int) { func (*ReceiptLog) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{24} return fileDescriptor_2cc4e03d2c28c490, []int{25}
} }
func (m *ReceiptLog) XXX_Unmarshal(b []byte) error { func (m *ReceiptLog) XXX_Unmarshal(b []byte) error {
...@@ -1470,7 +1541,7 @@ func (m *Receipt) Reset() { *m = Receipt{} } ...@@ -1470,7 +1541,7 @@ func (m *Receipt) Reset() { *m = Receipt{} }
func (m *Receipt) String() string { return proto.CompactTextString(m) } func (m *Receipt) String() string { return proto.CompactTextString(m) }
func (*Receipt) ProtoMessage() {} func (*Receipt) ProtoMessage() {}
func (*Receipt) Descriptor() ([]byte, []int) { func (*Receipt) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{25} return fileDescriptor_2cc4e03d2c28c490, []int{26}
} }
func (m *Receipt) XXX_Unmarshal(b []byte) error { func (m *Receipt) XXX_Unmarshal(b []byte) error {
...@@ -1524,7 +1595,7 @@ func (m *ReceiptData) Reset() { *m = ReceiptData{} } ...@@ -1524,7 +1595,7 @@ func (m *ReceiptData) Reset() { *m = ReceiptData{} }
func (m *ReceiptData) String() string { return proto.CompactTextString(m) } func (m *ReceiptData) String() string { return proto.CompactTextString(m) }
func (*ReceiptData) ProtoMessage() {} func (*ReceiptData) ProtoMessage() {}
func (*ReceiptData) Descriptor() ([]byte, []int) { func (*ReceiptData) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{26} return fileDescriptor_2cc4e03d2c28c490, []int{27}
} }
func (m *ReceiptData) XXX_Unmarshal(b []byte) error { func (m *ReceiptData) XXX_Unmarshal(b []byte) error {
...@@ -1575,7 +1646,7 @@ func (m *TxResult) Reset() { *m = TxResult{} } ...@@ -1575,7 +1646,7 @@ func (m *TxResult) Reset() { *m = TxResult{} }
func (m *TxResult) String() string { return proto.CompactTextString(m) } func (m *TxResult) String() string { return proto.CompactTextString(m) }
func (*TxResult) ProtoMessage() {} func (*TxResult) ProtoMessage() {}
func (*TxResult) Descriptor() ([]byte, []int) { func (*TxResult) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{27} return fileDescriptor_2cc4e03d2c28c490, []int{28}
} }
func (m *TxResult) XXX_Unmarshal(b []byte) error { func (m *TxResult) XXX_Unmarshal(b []byte) error {
...@@ -1658,7 +1729,7 @@ func (m *TransactionDetail) Reset() { *m = TransactionDetail{} } ...@@ -1658,7 +1729,7 @@ func (m *TransactionDetail) Reset() { *m = TransactionDetail{} }
func (m *TransactionDetail) String() string { return proto.CompactTextString(m) } func (m *TransactionDetail) String() string { return proto.CompactTextString(m) }
func (*TransactionDetail) ProtoMessage() {} func (*TransactionDetail) ProtoMessage() {}
func (*TransactionDetail) Descriptor() ([]byte, []int) { func (*TransactionDetail) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{28} return fileDescriptor_2cc4e03d2c28c490, []int{29}
} }
func (m *TransactionDetail) XXX_Unmarshal(b []byte) error { func (m *TransactionDetail) XXX_Unmarshal(b []byte) error {
...@@ -1760,7 +1831,7 @@ func (m *TransactionDetails) Reset() { *m = TransactionDetails{} } ...@@ -1760,7 +1831,7 @@ func (m *TransactionDetails) Reset() { *m = TransactionDetails{} }
func (m *TransactionDetails) String() string { return proto.CompactTextString(m) } func (m *TransactionDetails) String() string { return proto.CompactTextString(m) }
func (*TransactionDetails) ProtoMessage() {} func (*TransactionDetails) ProtoMessage() {}
func (*TransactionDetails) Descriptor() ([]byte, []int) { func (*TransactionDetails) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{29} return fileDescriptor_2cc4e03d2c28c490, []int{30}
} }
func (m *TransactionDetails) XXX_Unmarshal(b []byte) error { func (m *TransactionDetails) XXX_Unmarshal(b []byte) error {
...@@ -1799,7 +1870,7 @@ func (m *ReqAddrs) Reset() { *m = ReqAddrs{} } ...@@ -1799,7 +1870,7 @@ func (m *ReqAddrs) Reset() { *m = ReqAddrs{} }
func (m *ReqAddrs) String() string { return proto.CompactTextString(m) } func (m *ReqAddrs) String() string { return proto.CompactTextString(m) }
func (*ReqAddrs) ProtoMessage() {} func (*ReqAddrs) ProtoMessage() {}
func (*ReqAddrs) Descriptor() ([]byte, []int) { func (*ReqAddrs) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{30} return fileDescriptor_2cc4e03d2c28c490, []int{31}
} }
func (m *ReqAddrs) XXX_Unmarshal(b []byte) error { func (m *ReqAddrs) XXX_Unmarshal(b []byte) error {
...@@ -1838,7 +1909,7 @@ func (m *ReqDecodeRawTransaction) Reset() { *m = ReqDecodeRawTransaction ...@@ -1838,7 +1909,7 @@ func (m *ReqDecodeRawTransaction) Reset() { *m = ReqDecodeRawTransaction
func (m *ReqDecodeRawTransaction) String() string { return proto.CompactTextString(m) } func (m *ReqDecodeRawTransaction) String() string { return proto.CompactTextString(m) }
func (*ReqDecodeRawTransaction) ProtoMessage() {} func (*ReqDecodeRawTransaction) ProtoMessage() {}
func (*ReqDecodeRawTransaction) Descriptor() ([]byte, []int) { func (*ReqDecodeRawTransaction) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{31} return fileDescriptor_2cc4e03d2c28c490, []int{32}
} }
func (m *ReqDecodeRawTransaction) XXX_Unmarshal(b []byte) error { func (m *ReqDecodeRawTransaction) XXX_Unmarshal(b []byte) error {
...@@ -1878,7 +1949,7 @@ func (m *UserWrite) Reset() { *m = UserWrite{} } ...@@ -1878,7 +1949,7 @@ func (m *UserWrite) Reset() { *m = UserWrite{} }
func (m *UserWrite) String() string { return proto.CompactTextString(m) } func (m *UserWrite) String() string { return proto.CompactTextString(m) }
func (*UserWrite) ProtoMessage() {} func (*UserWrite) ProtoMessage() {}
func (*UserWrite) Descriptor() ([]byte, []int) { func (*UserWrite) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{32} return fileDescriptor_2cc4e03d2c28c490, []int{33}
} }
func (m *UserWrite) XXX_Unmarshal(b []byte) error { func (m *UserWrite) XXX_Unmarshal(b []byte) error {
...@@ -1926,7 +1997,7 @@ func (m *UpgradeMeta) Reset() { *m = UpgradeMeta{} } ...@@ -1926,7 +1997,7 @@ func (m *UpgradeMeta) Reset() { *m = UpgradeMeta{} }
func (m *UpgradeMeta) String() string { return proto.CompactTextString(m) } func (m *UpgradeMeta) String() string { return proto.CompactTextString(m) }
func (*UpgradeMeta) ProtoMessage() {} func (*UpgradeMeta) ProtoMessage() {}
func (*UpgradeMeta) Descriptor() ([]byte, []int) { func (*UpgradeMeta) Descriptor() ([]byte, []int) {
return fileDescriptor_2cc4e03d2c28c490, []int{33} return fileDescriptor_2cc4e03d2c28c490, []int{34}
} }
func (m *UpgradeMeta) XXX_Unmarshal(b []byte) error { func (m *UpgradeMeta) XXX_Unmarshal(b []byte) error {
...@@ -1975,6 +2046,7 @@ func init() { ...@@ -1975,6 +2046,7 @@ func init() {
proto.RegisterType((*AssetsTransfer)(nil), "types.AssetsTransfer") proto.RegisterType((*AssetsTransfer)(nil), "types.AssetsTransfer")
proto.RegisterType((*Asset)(nil), "types.Asset") proto.RegisterType((*Asset)(nil), "types.Asset")
proto.RegisterType((*CreateTx)(nil), "types.CreateTx") proto.RegisterType((*CreateTx)(nil), "types.CreateTx")
proto.RegisterType((*ReWriteRawTx)(nil), "types.ReWriteRawTx")
proto.RegisterType((*CreateTransactionGroup)(nil), "types.CreateTransactionGroup") proto.RegisterType((*CreateTransactionGroup)(nil), "types.CreateTransactionGroup")
proto.RegisterType((*UnsignTx)(nil), "types.UnsignTx") proto.RegisterType((*UnsignTx)(nil), "types.UnsignTx")
proto.RegisterType((*NoBalanceTx)(nil), "types.NoBalanceTx") proto.RegisterType((*NoBalanceTx)(nil), "types.NoBalanceTx")
...@@ -2008,87 +2080,89 @@ func init() { ...@@ -2008,87 +2080,89 @@ func init() {
func init() { proto.RegisterFile("transaction.proto", fileDescriptor_2cc4e03d2c28c490) } func init() { proto.RegisterFile("transaction.proto", fileDescriptor_2cc4e03d2c28c490) }
var fileDescriptor_2cc4e03d2c28c490 = []byte{ var fileDescriptor_2cc4e03d2c28c490 = []byte{
// 1306 bytes of a gzipped FileDescriptorProto // 1332 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xdd, 0x6e, 0x13, 0x47, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xdd, 0x6e, 0x13, 0x47,
0x14, 0xd6, 0xae, 0x7f, 0x62, 0x1f, 0x1b, 0x4a, 0x56, 0x28, 0x58, 0x88, 0x42, 0x3a, 0xa2, 0x12, 0x14, 0xd6, 0xee, 0xda, 0x89, 0x7d, 0x6c, 0x28, 0x59, 0x21, 0xb0, 0x10, 0x85, 0x74, 0x44, 0x25,
0x42, 0xc8, 0x91, 0x12, 0xee, 0x5a, 0xa9, 0x05, 0x52, 0x01, 0x0a, 0xd0, 0x76, 0x30, 0x50, 0xb5, 0x84, 0x50, 0x22, 0x25, 0xdc, 0xb5, 0x52, 0x0b, 0xa4, 0x02, 0x14, 0xa0, 0xed, 0x60, 0xa0, 0x6a,
0x55, 0xa5, 0xc9, 0xfa, 0xc4, 0x9e, 0xc6, 0xde, 0x71, 0x76, 0xc7, 0x61, 0xfd, 0x02, 0xbd, 0x69, 0xab, 0x4a, 0x93, 0xf5, 0x89, 0x3d, 0xc5, 0xde, 0x71, 0x76, 0xc7, 0x61, 0xfd, 0x02, 0xbd, 0x69,
0xef, 0xfa, 0x48, 0x7d, 0x81, 0x3e, 0x46, 0x1f, 0xa3, 0x9a, 0x33, 0x33, 0xbb, 0xe3, 0xfc, 0x20, 0xef, 0xfa, 0x48, 0x7d, 0x81, 0x3e, 0x46, 0x1f, 0xa3, 0x9a, 0x33, 0x33, 0xbb, 0xe3, 0x38, 0x41,
0x2e, 0x2a, 0xf5, 0x6e, 0xbe, 0x33, 0xc7, 0xe7, 0xf7, 0x3b, 0x67, 0xc7, 0xb0, 0xa9, 0x73, 0x91, 0x5c, 0x54, 0xea, 0xdd, 0x7c, 0x67, 0x8e, 0xcf, 0xcf, 0x77, 0x7e, 0x76, 0x0c, 0x5b, 0xba, 0x10,
0x15, 0x22, 0xd5, 0x52, 0x65, 0xc3, 0x45, 0xae, 0xb4, 0x4a, 0x5a, 0x7a, 0xb5, 0xc0, 0xe2, 0x66, 0x79, 0x29, 0x32, 0x2d, 0x55, 0xbe, 0x33, 0x2f, 0x94, 0x56, 0x69, 0x5b, 0x2f, 0xe7, 0x58, 0xde,
0x3f, 0x55, 0xf3, 0xb9, 0x17, 0xb2, 0x97, 0x70, 0xe5, 0x51, 0x51, 0xa0, 0x2e, 0x9e, 0x62, 0x86, 0xe8, 0x67, 0x6a, 0x36, 0xf3, 0x42, 0xf6, 0x02, 0x2e, 0x3d, 0x2c, 0x4b, 0xd4, 0xe5, 0x13, 0xcc,
0x85, 0x2c, 0x92, 0x2d, 0x68, 0x8b, 0xb9, 0x5a, 0x66, 0x7a, 0x10, 0x6f, 0x47, 0xf7, 0x1a, 0xdc, 0xb1, 0x94, 0x65, 0x7a, 0x0d, 0x36, 0xc4, 0x4c, 0x2d, 0x72, 0x3d, 0x88, 0xb7, 0xa3, 0xbb, 0x09,
0xa1, 0xe4, 0x2e, 0x5c, 0xc9, 0x51, 0x2f, 0xf3, 0xec, 0xd1, 0x78, 0x9c, 0x63, 0x51, 0x0c, 0x1a, 0x77, 0x28, 0xbd, 0x03, 0x97, 0x0a, 0xd4, 0x8b, 0x22, 0x7f, 0x38, 0x1a, 0x15, 0x58, 0x96, 0x83,
0xdb, 0xd1, 0xbd, 0x2e, 0x5f, 0x17, 0xb2, 0x3f, 0x22, 0xb8, 0x6e, 0xed, 0x8d, 0x8c, 0xff, 0x23, 0x64, 0x3b, 0xba, 0xdb, 0xe5, 0xab, 0x42, 0xf6, 0x47, 0x04, 0x57, 0xad, 0xbd, 0xa1, 0xf1, 0x7f,
0xcc, 0x47, 0xea, 0x9b, 0x12, 0xd3, 0xe4, 0x16, 0x74, 0x53, 0x25, 0x33, 0xad, 0x8e, 0x31, 0x1b, 0x8c, 0xc5, 0x50, 0x7d, 0x53, 0x61, 0x96, 0xde, 0x84, 0x6e, 0xa6, 0x64, 0xae, 0xd5, 0x3b, 0xcc,
0x44, 0xf4, 0xd3, 0x5a, 0x70, 0xa9, 0xd3, 0x04, 0x9a, 0x99, 0xd2, 0x48, 0xbe, 0xfa, 0x9c, 0xce, 0x07, 0x11, 0xfd, 0xb4, 0x11, 0x5c, 0xe8, 0x34, 0x85, 0x56, 0xae, 0x34, 0x92, 0xaf, 0x3e, 0xa7,
0xc9, 0x4d, 0xe8, 0x60, 0x89, 0xe9, 0x2b, 0x31, 0xc7, 0x41, 0x93, 0x0c, 0x55, 0x38, 0xb9, 0x0a, 0x73, 0x7a, 0x03, 0x3a, 0x58, 0x61, 0xf6, 0x52, 0xcc, 0x70, 0xd0, 0x22, 0x43, 0x35, 0x4e, 0x2f,
0xb1, 0x56, 0x83, 0x16, 0x49, 0x63, 0xad, 0xd8, 0x6f, 0x11, 0x5c, 0xb5, 0xe1, 0xbc, 0x93, 0x7a, 0x43, 0xac, 0xd5, 0xa0, 0x4d, 0xd2, 0x58, 0x2b, 0xf6, 0x5b, 0x04, 0x97, 0x6d, 0x38, 0x6f, 0xa5,
0x3a, 0xce, 0xc5, 0xfb, 0xff, 0x29, 0x90, 0x5f, 0x7d, 0x1c, 0xbe, 0x2c, 0xff, 0x61, 0x1c, 0xd6, 0x9e, 0x8c, 0x0a, 0xf1, 0xfe, 0x7f, 0x0a, 0xe4, 0x57, 0x1f, 0x87, 0xa7, 0xe5, 0x3f, 0x8c, 0xc3,
0x57, 0xb3, 0xf2, 0x75, 0x00, 0x2d, 0xf2, 0x65, 0x94, 0x4d, 0x40, 0xce, 0x3a, 0x9d, 0x8d, 0xe1, 0xfa, 0x6a, 0xd5, 0xbe, 0x0e, 0xa1, 0x4d, 0xbe, 0x8c, 0xb2, 0x09, 0xc8, 0x59, 0xa7, 0xb3, 0x31,
0x62, 0x35, 0x3f, 0x54, 0x33, 0x32, 0xdc, 0xe5, 0x0e, 0x05, 0x0e, 0x1b, 0xa1, 0x43, 0xf6, 0x4f, 0x5c, 0x2e, 0x67, 0x47, 0x6a, 0x4a, 0x86, 0xbb, 0xdc, 0xa1, 0xc0, 0x61, 0x12, 0x3a, 0x64, 0xff,
0x04, 0x9d, 0x27, 0x39, 0x0a, 0x8d, 0xa3, 0xd2, 0x79, 0x8a, 0xbc, 0xa7, 0x4b, 0xa3, 0xbc, 0x06, 0x44, 0xd0, 0x79, 0x5c, 0xa0, 0xd0, 0x38, 0xac, 0x9c, 0xa7, 0xc8, 0x7b, 0xba, 0x30, 0xca, 0x2b,
0x8d, 0x23, 0x44, 0x67, 0xc9, 0x1c, 0xab, 0xb8, 0x9b, 0x41, 0xdc, 0xb7, 0x01, 0x64, 0xd5, 0x17, 0x90, 0x1c, 0x23, 0x3a, 0x4b, 0xe6, 0x58, 0xc7, 0xdd, 0x0a, 0xe2, 0xbe, 0x05, 0x20, 0xeb, 0xba,
0xaa, 0x55, 0x87, 0x07, 0x92, 0x64, 0x00, 0x1b, 0xb2, 0x18, 0x51, 0x7d, 0xda, 0x74, 0xe9, 0x61, 0x10, 0x57, 0x1d, 0x1e, 0x48, 0xd2, 0x01, 0x6c, 0xca, 0x72, 0x48, 0xfc, 0x6c, 0xd0, 0xa5, 0x87,
0xb2, 0x0d, 0x3d, 0x2a, 0xd3, 0x6b, 0x9b, 0xc9, 0x06, 0x05, 0x14, 0x8a, 0xd6, 0x7a, 0xd3, 0x39, 0xe9, 0x36, 0xf4, 0x88, 0xa6, 0x57, 0x36, 0x93, 0x4d, 0x0a, 0x28, 0x14, 0xad, 0xd4, 0xa6, 0x73,
0xd3, 0x9b, 0x2d, 0x68, 0x9b, 0x33, 0xe6, 0x83, 0xae, 0x2d, 0x81, 0x45, 0xec, 0x3e, 0x6c, 0xb9, 0xa6, 0x36, 0xd7, 0x60, 0xc3, 0x9c, 0xb1, 0x18, 0x74, 0x2d, 0x05, 0x16, 0xb1, 0x39, 0xf4, 0x39,
0x4c, 0xeb, 0xd1, 0x79, 0x9a, 0xab, 0xe5, 0xc2, 0xe4, 0xa3, 0xcb, 0x62, 0x10, 0x6d, 0x37, 0xee, 0xbe, 0x2d, 0xa4, 0x46, 0x2e, 0xde, 0xbb, 0x6c, 0xab, 0x3a, 0xdb, 0x2a, 0xf8, 0x5d, 0x4c, 0x59,
0x75, 0xb9, 0x39, 0xb2, 0xdb, 0xd0, 0x79, 0x93, 0x15, 0x72, 0x92, 0x8d, 0x4a, 0x93, 0xdb, 0x58, 0x38, 0xe4, 0x58, 0x49, 0x42, 0x56, 0xb0, 0x9a, 0xcb, 0xc2, 0x77, 0x85, 0x43, 0x9e, 0x95, 0x76,
0x68, 0x41, 0x75, 0xe9, 0x73, 0x3a, 0x33, 0x05, 0xbd, 0x57, 0xea, 0xb1, 0x98, 0x89, 0x2c, 0x35, 0xcd, 0x0a, 0xbb, 0x07, 0xd7, 0x1c, 0xb7, 0xcd, 0xb0, 0x3e, 0x29, 0xd4, 0x62, 0x6e, 0x74, 0x75,
0x85, 0xbb, 0x0e, 0x2d, 0x5d, 0x3e, 0xc3, 0xd2, 0xd5, 0xce, 0x02, 0x93, 0xe0, 0x42, 0xac, 0xcc, 0x55, 0x0e, 0xa2, 0xed, 0xe4, 0x6e, 0x97, 0x9b, 0x23, 0xbb, 0x05, 0x9d, 0xd7, 0x79, 0x29, 0xc7,
0xe8, 0xb8, 0x66, 0x78, 0x48, 0x37, 0xb9, 0x3c, 0x3d, 0xc6, 0x95, 0x1b, 0x33, 0x0f, 0x6d, 0xf0, 0xf9, 0xb0, 0x32, 0x6c, 0x8e, 0x84, 0x16, 0x14, 0x5b, 0x9f, 0xd3, 0x99, 0x29, 0xe8, 0xbd, 0x54,
0x0b, 0x99, 0x7b, 0xca, 0x39, 0xc4, 0x7e, 0x81, 0xce, 0x6b, 0x39, 0xc9, 0x70, 0x3c, 0x2a, 0x8d, 0x8f, 0xc4, 0x54, 0xe4, 0x99, 0x29, 0xd5, 0x55, 0x68, 0xeb, 0xea, 0x29, 0xfa, 0xf8, 0x2d, 0x30,
0xce, 0x92, 0x82, 0x73, 0x21, 0x39, 0x64, 0x02, 0x25, 0x69, 0x6c, 0x03, 0x25, 0xd9, 0x16, 0xb4, 0x94, 0xce, 0xc5, 0xd2, 0x0c, 0xab, 0x2b, 0xbf, 0x87, 0x74, 0x53, 0xc8, 0xd3, 0x77, 0xb8, 0x74,
0x17, 0xcb, 0x43, 0xef, 0xa8, 0xcf, 0x1d, 0xa2, 0x56, 0xaf, 0xc8, 0x47, 0x8b, 0xc7, 0x7a, 0xc5, 0x99, 0x78, 0x78, 0x51, 0x3a, 0xec, 0x17, 0xe8, 0xbc, 0x92, 0xe3, 0x1c, 0x47, 0x43, 0xa2, 0x66,
0x7e, 0x8f, 0xa1, 0x17, 0xd4, 0x25, 0x28, 0xa2, 0xf3, 0x61, 0x91, 0xcb, 0x69, 0xa6, 0xc4, 0xd8, 0x41, 0xc1, 0xb9, 0x90, 0x1c, 0x32, 0x81, 0x92, 0xd4, 0x12, 0x46, 0x67, 0xa3, 0x3b, 0x5f, 0x1c,
0xb9, 0xf1, 0x30, 0x19, 0x42, 0xd7, 0x78, 0x14, 0x7a, 0x99, 0x5b, 0x6a, 0xf4, 0x76, 0xaf, 0x0d, 0x79, 0x47, 0x7d, 0xee, 0x10, 0xd1, 0xb8, 0x24, 0x1f, 0x6d, 0x1e, 0xeb, 0x25, 0xfb, 0x3d, 0x86,
0x69, 0x25, 0x0d, 0x5f, 0x7b, 0x39, 0xaf, 0x55, 0x3c, 0x89, 0x9a, 0x35, 0x89, 0xea, 0xdc, 0x5b, 0x5e, 0xc0, 0x4b, 0x40, 0x7f, 0xb4, 0x42, 0xbf, 0xcd, 0x69, 0xaa, 0xc4, 0xc8, 0xb9, 0xf1, 0x30,
0x96, 0x6e, 0x16, 0x99, 0xea, 0x66, 0x2a, 0x4b, 0x91, 0x68, 0xd2, 0xe0, 0x16, 0x38, 0xb2, 0x6e, 0xdd, 0x81, 0xae, 0xf1, 0x28, 0xf4, 0xa2, 0xb0, 0xcd, 0xd8, 0xdb, 0xbb, 0xb2, 0x43, 0x4b, 0x70,
0x54, 0x64, 0xbd, 0x0d, 0x30, 0x31, 0xdd, 0x7c, 0x42, 0x84, 0xed, 0x50, 0x66, 0x81, 0xc4, 0x58, 0xe7, 0x95, 0x97, 0xf3, 0x46, 0xc5, 0x17, 0xa8, 0xd5, 0xb4, 0x6d, 0x93, 0xbb, 0xad, 0x9a, 0x2f,
0x9f, 0xa2, 0x18, 0x3b, 0x5a, 0xf4, 0xb9, 0x43, 0x44, 0x5d, 0x2c, 0xf5, 0x00, 0x1c, 0x75, 0xb1, 0xe5, 0x55, 0x68, 0xe7, 0x2a, 0xcf, 0x90, 0x1a, 0x33, 0xe1, 0x16, 0xb8, 0x46, 0xd8, 0xac, 0x1b,
0xd4, 0xec, 0x21, 0xf4, 0x83, 0x62, 0x14, 0xc9, 0xdd, 0x9a, 0x20, 0xbd, 0xdd, 0xc4, 0x65, 0x15, 0xe1, 0x16, 0xc0, 0xd8, 0x54, 0xf3, 0x31, 0x8d, 0x48, 0x87, 0x32, 0x0b, 0x24, 0xc6, 0xfa, 0x04,
0x68, 0x58, 0xd2, 0x7c, 0x05, 0x57, 0xb8, 0xcc, 0x26, 0x55, 0xb6, 0xc9, 0x10, 0x5a, 0x52, 0xe3, 0xc5, 0xc8, 0x35, 0x62, 0x9f, 0x3b, 0x44, 0xc3, 0x82, 0x95, 0x1e, 0x80, 0x1b, 0x16, 0xac, 0x34,
0xdc, 0xff, 0x70, 0xe0, 0x7e, 0xb8, 0xa6, 0xf4, 0x5c, 0xe3, 0x9c, 0x5b, 0x35, 0xf6, 0x1c, 0x36, 0x7b, 0x00, 0xfd, 0x80, 0x8c, 0x32, 0xbd, 0xd3, 0x34, 0x48, 0x6f, 0x2f, 0x75, 0x59, 0x05, 0x1a,
0xcf, 0xdd, 0x05, 0x1d, 0x34, 0x56, 0xea, 0x0e, 0xde, 0x0a, 0xeb, 0x1d, 0xd3, 0x55, 0x2d, 0x60, 0xb6, 0x69, 0xbe, 0x82, 0x4b, 0x5c, 0xe6, 0xe3, 0x3a, 0xdb, 0x74, 0x07, 0xda, 0x52, 0xe3, 0xcc,
0xdf, 0x43, 0xb7, 0x8e, 0xc3, 0x36, 0x3b, 0xf2, 0xcd, 0x0e, 0x4c, 0xc6, 0x6b, 0xa4, 0xb8, 0x75, 0xff, 0x70, 0xe0, 0x7e, 0xb8, 0xa2, 0xf4, 0x4c, 0xe3, 0x8c, 0x5b, 0x35, 0xf6, 0x0c, 0xb6, 0xd6,
0xb6, 0x85, 0x6b, 0x26, 0x7f, 0x86, 0xbe, 0x21, 0xef, 0xb7, 0xa7, 0x98, 0x9f, 0x4a, 0xa4, 0xf9, 0xee, 0x82, 0x0a, 0x1a, 0x2b, 0x4d, 0x05, 0x6f, 0x86, 0x7c, 0xc7, 0x74, 0xd5, 0x08, 0xd8, 0xf7,
0xcd, 0x31, 0x95, 0xa7, 0x8e, 0x23, 0x0d, 0xee, 0xa1, 0xb9, 0x39, 0xb4, 0xb3, 0xe1, 0x16, 0x87, 0xd0, 0x6d, 0xe2, 0xb0, 0xc5, 0x8e, 0x7c, 0xb1, 0x03, 0x93, 0xf1, 0x4a, 0x53, 0xdc, 0x3c, 0x5b,
0x87, 0xe6, 0x46, 0x97, 0x4f, 0x82, 0x3d, 0xe4, 0x21, 0xfb, 0x33, 0x82, 0x0d, 0x8e, 0x27, 0x34, 0xc2, 0x15, 0x93, 0x3f, 0x43, 0xdf, 0x34, 0xef, 0xb7, 0xa7, 0x58, 0x9c, 0x4a, 0xa4, 0x8d, 0x51,
0x1e, 0x09, 0x34, 0x85, 0x99, 0x1a, 0xb7, 0xd8, 0x84, 0x93, 0x1d, 0xcd, 0xc4, 0x84, 0x0c, 0xb6, 0x60, 0x26, 0x4f, 0x5d, 0x8f, 0x24, 0xdc, 0x43, 0x73, 0x73, 0x64, 0x67, 0xc3, 0xad, 0x2a, 0x0f,
0x38, 0x9d, 0x0d, 0x31, 0xd2, 0xca, 0x56, 0x8b, 0x5b, 0x60, 0xb2, 0x18, 0xcb, 0x1c, 0xa9, 0x31, 0xcd, 0x8d, 0xae, 0x1e, 0x07, 0x9b, 0xcf, 0x43, 0xf6, 0x67, 0x04, 0x9b, 0x1c, 0x4f, 0x68, 0x3c,
0x8e, 0xe1, 0xb5, 0xc0, 0xd2, 0x40, 0x4e, 0xa6, 0xda, 0x93, 0xcc, 0x22, 0x63, 0x4b, 0x66, 0x63, 0x52, 0x68, 0x09, 0x33, 0x35, 0x6e, 0x95, 0x0a, 0x27, 0x3b, 0x9e, 0x8a, 0x31, 0x19, 0x6c, 0x73,
0x2c, 0x3d, 0xc9, 0x08, 0xb0, 0x1f, 0x00, 0x38, 0x9e, 0x7c, 0x97, 0xcb, 0x53, 0x91, 0xae, 0x6a, 0x3a, 0x9b, 0xc6, 0xc8, 0x6a, 0x5b, 0x6d, 0x6e, 0x81, 0xc9, 0x62, 0x24, 0x0b, 0xa4, 0xc2, 0xb8,
0x7f, 0xd1, 0xa5, 0xfe, 0xe2, 0xcb, 0xfd, 0x35, 0x42, 0x7f, 0xec, 0x06, 0xb4, 0x9e, 0x61, 0xe9, 0x0e, 0x6f, 0x04, 0xb6, 0x0d, 0xe4, 0x78, 0xa2, 0x7d, 0x93, 0x59, 0x64, 0x6c, 0xc9, 0x7c, 0x84,
0x96, 0x6e, 0x59, 0x2d, 0xdd, 0x92, 0x2d, 0xa1, 0xc7, 0x71, 0x31, 0x5b, 0x8d, 0xca, 0xe7, 0xd9, 0x95, 0x6f, 0x32, 0x02, 0xec, 0x07, 0x00, 0x8e, 0x27, 0xdf, 0x15, 0xf2, 0x54, 0x64, 0xcb, 0xc6,
0x91, 0x32, 0x79, 0x4f, 0x45, 0x31, 0xf5, 0xdb, 0xc7, 0x9c, 0x03, 0x9b, 0xf1, 0xc5, 0x39, 0x34, 0x5f, 0x74, 0xa1, 0xbf, 0xf8, 0x62, 0x7f, 0x49, 0xe8, 0x8f, 0x5d, 0x87, 0xf6, 0x53, 0xac, 0xd6,
0x82, 0x1c, 0x92, 0xbb, 0xd0, 0x16, 0xf4, 0x6d, 0x1a, 0x34, 0x89, 0x86, 0x7d, 0x47, 0x43, 0xfa, 0x17, 0x1f, 0x5b, 0x40, 0x8f, 0xe3, 0x7c, 0xba, 0x1c, 0x56, 0xcf, 0xf2, 0x63, 0x65, 0xf2, 0x9e,
0x88, 0x70, 0x77, 0xc7, 0x3e, 0x83, 0x2e, 0xc7, 0x93, 0x51, 0xf9, 0x42, 0x16, 0x7a, 0x3d, 0xd1, 0x88, 0x72, 0xe2, 0xb7, 0x8f, 0x39, 0x07, 0x36, 0xe3, 0xf3, 0x73, 0x48, 0x82, 0x1c, 0xd2, 0x3b,
0x86, 0x4b, 0x94, 0xed, 0x55, 0x91, 0x91, 0xd2, 0xc7, 0x0d, 0x05, 0x07, 0x18, 0x95, 0xcf, 0x44, 0xb0, 0x21, 0xe8, 0x6b, 0x38, 0x68, 0x51, 0x1b, 0xf6, 0x5d, 0x1b, 0xd2, 0x67, 0x8b, 0xbb, 0x3b,
0x31, 0xa5, 0xdf, 0x98, 0xc8, 0x45, 0x31, 0xc5, 0xc2, 0x93, 0xd9, 0xa2, 0xda, 0x61, 0x1c, 0x38, 0xf6, 0x19, 0x74, 0x39, 0x9e, 0x0c, 0xab, 0xe7, 0xb2, 0xd4, 0xab, 0x89, 0x26, 0x2e, 0x51, 0xb6,
0x0c, 0x16, 0x42, 0x63, 0xbb, 0x51, 0x2f, 0x04, 0xf6, 0x25, 0xf4, 0x83, 0x12, 0x15, 0xc9, 0x03, 0x5f, 0x47, 0x46, 0x4a, 0x1f, 0x37, 0x14, 0x1c, 0x60, 0x58, 0x3d, 0x15, 0xe5, 0x84, 0x7e, 0x63,
0xc3, 0x2a, 0x3a, 0x9e, 0x89, 0x26, 0xd0, 0xe2, 0x5e, 0x85, 0x0d, 0x4d, 0x4f, 0x53, 0x94, 0x0b, 0x22, 0x17, 0xe5, 0x04, 0x4b, 0xdf, 0xcc, 0x16, 0x35, 0x0e, 0xe3, 0xc0, 0x61, 0xb0, 0x10, 0x92,
0xfd, 0x42, 0x4d, 0xce, 0xcd, 0xc6, 0x35, 0x68, 0xcc, 0xd4, 0xc4, 0x0d, 0x86, 0x39, 0x32, 0x61, 0xed, 0xa4, 0x59, 0x08, 0xec, 0x4b, 0xf3, 0xed, 0xa8, 0x29, 0x2a, 0xd3, 0xfb, 0xa6, 0xab, 0xe8,
0x88, 0x49, 0xfa, 0xe7, 0x94, 0xef, 0x40, 0x7c, 0xf0, 0x96, 0x86, 0xaf, 0xb7, 0xfb, 0x89, 0xf3, 0x78, 0x26, 0x9a, 0x40, 0x8b, 0x7b, 0x15, 0xb6, 0x63, 0x6a, 0x9a, 0xa1, 0x9c, 0xeb, 0xe7, 0x6a,
0x79, 0x80, 0xab, 0xb7, 0x62, 0xb6, 0x44, 0x1e, 0x1f, 0xbc, 0x4d, 0x3e, 0x87, 0xe6, 0x4c, 0x4d, 0xbc, 0x36, 0x1b, 0x57, 0x20, 0x99, 0xaa, 0xb1, 0x1b, 0x0c, 0x73, 0x64, 0xc2, 0x34, 0x26, 0xe9,
0x0a, 0x8a, 0xbf, 0xb7, 0xbb, 0x59, 0x85, 0xe5, 0xdd, 0x73, 0xba, 0x66, 0xfb, 0xa6, 0xb2, 0x24, 0xaf, 0x29, 0xdf, 0x86, 0xf8, 0xf0, 0x0d, 0x0d, 0x5f, 0x6f, 0xef, 0x13, 0xe7, 0xf3, 0x10, 0x97,
0xdb, 0x17, 0x5a, 0x9c, 0x73, 0xf3, 0x91, 0x56, 0xfe, 0x8e, 0xa0, 0x33, 0x2a, 0x39, 0x16, 0xcb, 0x6f, 0xc4, 0x74, 0x81, 0x3c, 0x3e, 0x7c, 0x93, 0x7e, 0x0e, 0xad, 0xa9, 0x1a, 0x97, 0x14, 0x7f,
0x99, 0x0e, 0x38, 0x12, 0x5d, 0xcc, 0x11, 0xcb, 0x54, 0xc7, 0x11, 0x46, 0x24, 0xb4, 0x5b, 0xfb, 0x6f, 0x6f, 0xab, 0x0e, 0xcb, 0xbb, 0xe7, 0x74, 0xcd, 0x0e, 0x0c, 0xb3, 0x24, 0x3b, 0x10, 0x5a,
0xa2, 0x56, 0xc6, 0xba, 0x4c, 0x1e, 0x42, 0x2f, 0xb7, 0x2e, 0xc7, 0xc2, 0x7d, 0xea, 0xc3, 0x4a, 0xac, 0xb9, 0xf9, 0x48, 0x2b, 0x7f, 0x47, 0xd0, 0x19, 0x56, 0x1c, 0xcb, 0xc5, 0x54, 0x07, 0x3d,
0x57, 0xe1, 0xf3, 0x50, 0xcd, 0x4c, 0xc7, 0xe1, 0x4c, 0xa5, 0xc7, 0x5a, 0xce, 0xfd, 0x5e, 0xaf, 0x12, 0x9d, 0xdf, 0x23, 0xb6, 0x53, 0x5d, 0x8f, 0x30, 0x6a, 0x42, 0xbb, 0xb5, 0xcf, 0x2b, 0xa5,
0x05, 0x66, 0x69, 0x5b, 0x0f, 0xf4, 0x25, 0x6f, 0xd3, 0x10, 0x04, 0x12, 0xf6, 0x57, 0x0c, 0x9b, 0xf9, 0x22, 0x3f, 0x80, 0x5e, 0x61, 0x5d, 0x8e, 0x84, 0x7b, 0x5c, 0x84, 0x4c, 0xd7, 0xe1, 0xf3,
0x41, 0x1c, 0xfb, 0xa8, 0x85, 0x9c, 0xb9, 0x68, 0xa3, 0x0f, 0x46, 0xfb, 0x80, 0xb6, 0x93, 0x09, 0x50, 0xcd, 0x4c, 0xc7, 0xd1, 0x54, 0x65, 0xef, 0xb4, 0x9c, 0xf9, 0xbd, 0xde, 0x08, 0xcc, 0xd2,
0x83, 0x32, 0xbd, 0x38, 0x52, 0xaf, 0x42, 0x1b, 0x31, 0x57, 0xea, 0xc8, 0xd6, 0xd8, 0x6c, 0x44, 0xb6, 0x1e, 0xe8, 0xed, 0xb0, 0x41, 0x43, 0x10, 0x48, 0xd8, 0x5f, 0x31, 0x6c, 0x05, 0x71, 0x1c,
0x42, 0x41, 0x15, 0x9b, 0x17, 0x57, 0xb1, 0x15, 0x4e, 0xda, 0x5a, 0xae, 0xed, 0xb3, 0xb9, 0xd6, 0xa0, 0x16, 0x72, 0xea, 0xa2, 0x8d, 0x3e, 0x18, 0xed, 0x7d, 0xda, 0x4e, 0x26, 0x0c, 0xca, 0xf4,
0xaf, 0xa9, 0x8d, 0xb5, 0xd7, 0xd4, 0x4d, 0xe8, 0x1c, 0xe5, 0x6a, 0x4e, 0x1b, 0xcf, 0xbd, 0x65, 0xfc, 0x48, 0xbd, 0x0a, 0x6d, 0xc4, 0x42, 0xa9, 0x63, 0xcb, 0xb1, 0xd9, 0x88, 0x84, 0x02, 0x16,
0x3c, 0x3e, 0x53, 0x9f, 0xee, 0xd9, 0xfa, 0x04, 0xb3, 0x0d, 0x1f, 0x98, 0xed, 0xaf, 0x21, 0x39, 0x5b, 0xe7, 0xb3, 0xd8, 0x0e, 0x27, 0x6d, 0x25, 0xd7, 0x8d, 0xb3, 0xb9, 0x36, 0xef, 0xb7, 0xcd,
0x57, 0xc4, 0x22, 0xb9, 0x1f, 0xce, 0xef, 0xe0, 0x7c, 0x19, 0xad, 0x9e, 0x9d, 0xe2, 0x6d, 0xe8, 0x95, 0xf7, 0xdb, 0x0d, 0xe8, 0x1c, 0x17, 0x6a, 0x46, 0x1b, 0xcf, 0xbd, 0x9e, 0x3c, 0x3e, 0xc3,
0xb8, 0xe5, 0x4c, 0xb3, 0x6a, 0x62, 0xf3, 0xef, 0x25, 0x0b, 0xd8, 0x0e, 0xdc, 0xe0, 0x78, 0xb2, 0x4f, 0xf7, 0x2c, 0x3f, 0xc1, 0x6c, 0xc3, 0x07, 0x66, 0xfb, 0x6b, 0x48, 0xd7, 0x48, 0x2c, 0xd3,
0x8f, 0xa9, 0x1a, 0x23, 0x17, 0xef, 0xc3, 0xb7, 0xc4, 0x85, 0xaf, 0x23, 0xf6, 0x05, 0x74, 0xdf, 0x7b, 0xe1, 0xfc, 0x0e, 0xd6, 0x69, 0xb4, 0x7a, 0x76, 0x8a, 0xb7, 0xa1, 0xe3, 0x96, 0x33, 0xcd,
0x14, 0x98, 0xbf, 0xcb, 0xa5, 0xa6, 0x4f, 0xbc, 0x56, 0x0b, 0x99, 0x56, 0x2a, 0x06, 0x98, 0xaf, 0xaa, 0x89, 0xcd, 0xbf, 0x97, 0x2c, 0x60, 0xbb, 0x70, 0x9d, 0xe3, 0xc9, 0x01, 0x66, 0x6a, 0x44,
0x45, 0xaa, 0x32, 0x8d, 0x6e, 0x2f, 0x74, 0xb9, 0x87, 0xec, 0x27, 0xe8, 0xbd, 0x59, 0x4c, 0x72, 0x2f, 0xba, 0xe0, 0x2d, 0x71, 0xee, 0xeb, 0x88, 0x7d, 0x01, 0xdd, 0xd7, 0x25, 0x16, 0xf4, 0x04,
0x31, 0xc6, 0x97, 0xa8, 0x85, 0x29, 0x21, 0x75, 0x40, 0x66, 0x13, 0xb2, 0xd0, 0xe1, 0x15, 0x36, 0x24, 0x15, 0x35, 0x97, 0x59, 0xad, 0x62, 0x80, 0xf9, 0x5a, 0x64, 0x2a, 0xd7, 0xe8, 0xf6, 0x42,
0x46, 0x4e, 0x31, 0x2f, 0xfc, 0x72, 0xee, 0x72, 0x0f, 0x2f, 0x5b, 0xcd, 0x8f, 0xef, 0xfc, 0xf8, 0x97, 0x7b, 0xc8, 0x7e, 0x82, 0xde, 0xeb, 0xf9, 0xb8, 0x10, 0x23, 0x7c, 0x81, 0x5a, 0x18, 0x0a,
0xe9, 0x44, 0xea, 0xe9, 0xf2, 0x70, 0x98, 0xaa, 0xf9, 0xce, 0xde, 0x5e, 0x9a, 0xed, 0xa4, 0x53, 0xa9, 0x02, 0x32, 0x1f, 0x93, 0x85, 0x0e, 0xaf, 0xb1, 0x31, 0x72, 0x8a, 0x45, 0xe9, 0x97, 0x73,
0x21, 0xb3, 0xbd, 0xbd, 0x1d, 0x2a, 0xd2, 0x61, 0x9b, 0xfe, 0x5b, 0xed, 0xfd, 0x1b, 0x00, 0x00, 0x97, 0x7b, 0x78, 0xd1, 0x6a, 0x7e, 0x74, 0xfb, 0xc7, 0x4f, 0xc7, 0x52, 0x4f, 0x16, 0x47, 0x3b,
0xff, 0xff, 0xc0, 0xaa, 0xbd, 0xba, 0x85, 0x0d, 0x00, 0x00, 0x99, 0x9a, 0xed, 0xee, 0xef, 0x67, 0xf9, 0x6e, 0x36, 0x11, 0x32, 0xdf, 0xdf, 0xdf, 0x25, 0x92,
0x8e, 0x36, 0xe8, 0xdf, 0xdc, 0xfe, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x81, 0x12, 0x52, 0x09,
0xf7, 0x0d, 0x00, 0x00,
} }
...@@ -10,6 +10,8 @@ import ( ...@@ -10,6 +10,8 @@ import (
"encoding/json" "encoding/json"
"time" "time"
"strconv"
"github.com/33cn/chain33/common" "github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address" "github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/crypto" "github.com/33cn/chain33/common/crypto"
...@@ -601,3 +603,37 @@ func (tx *Transaction) IsWithdraw() bool { ...@@ -601,3 +603,37 @@ func (tx *Transaction) IsWithdraw() bool {
} }
return false return false
} }
// ParseExpire parse expire to int from during or height
func ParseExpire(expire string) (int64, error) {
if len(expire) == 0 {
return 0, ErrInvalidParam
}
if expire[0] == 'H' && expire[1] == ':' {
txHeight, err := strconv.ParseInt(expire[2:], 10, 64)
if err != nil {
return 0, err
}
if txHeight <= 0 {
//fmt.Printf("txHeight should be grate to 0")
return 0, ErrHeightLessZero
}
if txHeight+TxHeightFlag < txHeight {
return 0, ErrHeightOverflow
}
return txHeight + TxHeightFlag, nil
}
blockHeight, err := strconv.ParseInt(expire, 10, 64)
if err == nil {
return blockHeight, nil
}
expireTime, err := time.ParseDuration(expire)
if err == nil {
return int64(expireTime), nil
}
return 0, err
}
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"github.com/33cn/chain33/common/crypto" "github.com/33cn/chain33/common/crypto"
_ "github.com/33cn/chain33/system/crypto/init" _ "github.com/33cn/chain33/system/crypto/init"
"github.com/stretchr/testify/assert"
) )
func TestCreateGroupTx(t *testing.T) { func TestCreateGroupTx(t *testing.T) {
...@@ -135,3 +136,28 @@ func BenchmarkTxHash(b *testing.B) { ...@@ -135,3 +136,28 @@ func BenchmarkTxHash(b *testing.B) {
tx12.Hash() tx12.Hash()
} }
} }
func TestParseExpire(t *testing.T) {
expire := ""
_, err := ParseExpire(expire)
assert.Equal(t, ErrInvalidParam, err)
expire = "H:123"
exp, _ := ParseExpire(expire)
assert.Equal(t, int64(4611686018427388027), exp)
expire = "H:-2"
_, err = ParseExpire(expire)
assert.Equal(t, ErrHeightLessZero, err)
expire = "123"
exp, err = ParseExpire(expire)
assert.Nil(t, err)
assert.Equal(t, int64(123), exp)
expire = "123s"
exp, err = ParseExpire(expire)
assert.Nil(t, err)
assert.Equal(t, int64(123000000000), exp)
}
...@@ -1355,6 +1355,9 @@ type ReqSignRawTx struct { ...@@ -1355,6 +1355,9 @@ type ReqSignRawTx struct {
// 1:隐私交易 // 1:隐私交易
// int32 mode = 6; // int32 mode = 6;
Token string `protobuf:"bytes,7,opt,name=token,proto3" json:"token,omitempty"` Token string `protobuf:"bytes,7,opt,name=token,proto3" json:"token,omitempty"`
Fee int64 `protobuf:"varint,8,opt,name=fee,proto3" json:"fee,omitempty"`
NewExecer []byte `protobuf:"bytes,9,opt,name=newExecer,proto3" json:"newExecer,omitempty"`
NewToAddr string `protobuf:"bytes,10,opt,name=newToAddr,proto3" json:"newToAddr,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -1427,6 +1430,27 @@ func (m *ReqSignRawTx) GetToken() string { ...@@ -1427,6 +1430,27 @@ func (m *ReqSignRawTx) GetToken() string {
return "" return ""
} }
func (m *ReqSignRawTx) GetFee() int64 {
if m != nil {
return m.Fee
}
return 0
}
func (m *ReqSignRawTx) GetNewExecer() []byte {
if m != nil {
return m.NewExecer
}
return nil
}
func (m *ReqSignRawTx) GetNewToAddr() string {
if m != nil {
return m.NewToAddr
}
return ""
}
type ReplySignRawTx struct { type ReplySignRawTx struct {
TxHex string `protobuf:"bytes,1,opt,name=txHex,proto3" json:"txHex,omitempty"` TxHex string `protobuf:"bytes,1,opt,name=txHex,proto3" json:"txHex,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
...@@ -1747,85 +1771,87 @@ func init() { ...@@ -1747,85 +1771,87 @@ func init() {
func init() { proto.RegisterFile("wallet.proto", fileDescriptor_b88fd140af4deb6f) } func init() { proto.RegisterFile("wallet.proto", fileDescriptor_b88fd140af4deb6f) }
var fileDescriptor_b88fd140af4deb6f = []byte{ var fileDescriptor_b88fd140af4deb6f = []byte{
// 1271 bytes of a gzipped FileDescriptorProto // 1305 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x5d, 0x6e, 0x1b, 0xb7, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x5f, 0x6e, 0x1b, 0x37,
0x13, 0xc7, 0x4a, 0x96, 0x6d, 0xd1, 0xb2, 0x93, 0x10, 0x49, 0xb0, 0xf0, 0xff, 0x9f, 0x44, 0x61, 0x13, 0xc7, 0x4a, 0x96, 0x6d, 0xd1, 0xb2, 0x93, 0x2c, 0x92, 0x40, 0xf0, 0xf7, 0x25, 0x71, 0x58,
0x91, 0xd4, 0x05, 0x0a, 0x07, 0x88, 0x5e, 0x8a, 0x02, 0x05, 0xe2, 0x7c, 0x3a, 0x80, 0x93, 0x1a, 0x24, 0x75, 0x81, 0xc2, 0x01, 0xa2, 0x97, 0xa2, 0x40, 0x81, 0x38, 0x7f, 0x1d, 0xc0, 0x49, 0x0d,
0x94, 0x8a, 0x02, 0x7d, 0x29, 0xa8, 0x5d, 0x5a, 0x22, 0xb4, 0x5a, 0xae, 0xb9, 0xd4, 0xd7, 0x45, 0x4a, 0x45, 0x81, 0xbe, 0x14, 0xd4, 0xee, 0x58, 0x22, 0xb4, 0x5a, 0xae, 0xb9, 0x94, 0x25, 0xdd,
0x8a, 0x1e, 0xa0, 0x47, 0xe8, 0x45, 0x7a, 0x8f, 0x1e, 0xa2, 0x98, 0x21, 0xb9, 0xda, 0x4d, 0xdc, 0xa4, 0x07, 0xe8, 0x11, 0x7a, 0x91, 0xde, 0xa1, 0x8f, 0x3d, 0x44, 0x31, 0x43, 0x52, 0xbb, 0x9b,
0x87, 0xa0, 0x6f, 0xf3, 0x1b, 0x0e, 0x67, 0x38, 0xbf, 0x19, 0x0e, 0x49, 0x7a, 0x2b, 0x91, 0x65, 0xb8, 0x0f, 0x41, 0xdf, 0xf8, 0x1b, 0x0e, 0x67, 0x38, 0xbf, 0x19, 0x0e, 0x87, 0xf5, 0x96, 0x32,
0xd2, 0x9e, 0x16, 0x46, 0x5b, 0x4d, 0x3b, 0x76, 0x53, 0xc8, 0xf2, 0xf8, 0x8e, 0x35, 0x22, 0x2f, 0xcb, 0xc0, 0x9e, 0x14, 0x46, 0x5b, 0x1d, 0x77, 0xec, 0xba, 0x80, 0xf2, 0xf0, 0x8e, 0x35, 0x32,
0x45, 0x62, 0x95, 0xce, 0xdd, 0xca, 0xf1, 0xed, 0x71, 0xa6, 0x93, 0x59, 0x32, 0x15, 0x2a, 0x68, 0x2f, 0x65, 0x62, 0x95, 0xce, 0xdd, 0xce, 0xe1, 0xed, 0x71, 0xa6, 0x93, 0x59, 0x32, 0x95, 0x2a,
0x0e, 0x45, 0x92, 0xe8, 0x45, 0xee, 0xb7, 0x1e, 0x1f, 0xc9, 0xb5, 0x4c, 0x16, 0x56, 0x1b, 0x87, 0x48, 0xf6, 0x65, 0x92, 0xe8, 0x45, 0xee, 0x8f, 0x1e, 0x1e, 0xc0, 0x0a, 0x92, 0x85, 0xd5, 0xc6,
0xd9, 0x9f, 0x2d, 0x72, 0xf4, 0x33, 0xfa, 0x1e, 0xad, 0x5f, 0x4b, 0x2b, 0x54, 0x46, 0x19, 0x69, 0x61, 0xfe, 0x47, 0x8b, 0x1d, 0xfc, 0x4c, 0xb6, 0x47, 0xab, 0xd7, 0x60, 0xa5, 0xca, 0x62, 0xce,
0xd9, 0x75, 0x1c, 0xf5, 0xa3, 0x93, 0x83, 0xe7, 0xf4, 0x14, 0x43, 0x9d, 0x8e, 0xb6, 0x91, 0x78, 0x5a, 0x76, 0xd5, 0x8f, 0x8e, 0xa2, 0xe3, 0xbd, 0xe7, 0xf1, 0x09, 0xb9, 0x3a, 0x19, 0x55, 0x9e,
0xcb, 0xae, 0xe9, 0xb7, 0x64, 0xcf, 0xc8, 0x44, 0xaa, 0xc2, 0xc6, 0xad, 0x86, 0x21, 0x77, 0xda, 0x44, 0xcb, 0xae, 0xe2, 0x6f, 0xd9, 0x8e, 0x81, 0x04, 0x54, 0x61, 0xfb, 0xad, 0x86, 0xa2, 0x70,
0xd7, 0xc2, 0x0a, 0x1e, 0x4c, 0xe8, 0x7d, 0xb2, 0x3b, 0x95, 0x6a, 0x32, 0xb5, 0x71, 0xbb, 0x1f, 0xd2, 0xd7, 0xd2, 0x4a, 0x11, 0x54, 0xe2, 0xfb, 0x6c, 0x7b, 0x0a, 0x6a, 0x32, 0xb5, 0xfd, 0xf6,
0x9d, 0xb4, 0xb9, 0x47, 0xf4, 0x2e, 0xe9, 0xa8, 0x3c, 0x95, 0xeb, 0x78, 0x07, 0xd5, 0x0e, 0xd0, 0x51, 0x74, 0xdc, 0x16, 0x1e, 0xc5, 0x77, 0x59, 0x47, 0xe5, 0x29, 0xac, 0xfa, 0x5b, 0x24, 0x76,
0xff, 0x93, 0x2e, 0x66, 0x61, 0xd5, 0x5c, 0xc6, 0x1d, 0x5c, 0xd9, 0x2a, 0xc0, 0x97, 0x98, 0x43, 0x20, 0xfe, 0x3f, 0xeb, 0x52, 0x14, 0x56, 0xcd, 0xa1, 0xdf, 0xa1, 0x9d, 0x4a, 0x80, 0xb6, 0xe4,
0x42, 0xf1, 0xae, 0xf3, 0xe5, 0x10, 0x3d, 0x26, 0xfb, 0x57, 0x46, 0xcf, 0x45, 0x9a, 0x9a, 0x78, 0x1c, 0x03, 0xea, 0x6f, 0x3b, 0x5b, 0x0e, 0xc5, 0x87, 0x6c, 0xf7, 0xd2, 0xe8, 0xb9, 0x4c, 0x53,
0xaf, 0x1f, 0x9d, 0x74, 0x79, 0x85, 0x61, 0x8f, 0x5d, 0x4f, 0x45, 0x39, 0x8d, 0xf7, 0xfb, 0xd1, 0xd3, 0xdf, 0x39, 0x8a, 0x8e, 0xbb, 0x62, 0x83, 0xf1, 0x8c, 0x5d, 0x4d, 0x65, 0x39, 0xed, 0xef,
0x49, 0x8f, 0x7b, 0x44, 0x1f, 0x12, 0xe2, 0x72, 0xfa, 0x28, 0xe6, 0x32, 0xee, 0xe2, 0xae, 0x9a, 0x1e, 0x45, 0xc7, 0x3d, 0xe1, 0x51, 0xfc, 0x90, 0x31, 0x17, 0xd3, 0x47, 0x39, 0x87, 0x7e, 0x97,
0x86, 0xc6, 0x64, 0xaf, 0x10, 0x9b, 0x4c, 0x8b, 0x34, 0x26, 0xb8, 0x31, 0x40, 0xf6, 0x96, 0xdc, 0x4e, 0xd5, 0x24, 0x71, 0x9f, 0xed, 0x14, 0x72, 0x9d, 0x69, 0x99, 0xf6, 0x19, 0x1d, 0x0c, 0x90,
0x6a, 0xb2, 0x56, 0xd2, 0x01, 0xe9, 0xda, 0x00, 0xe2, 0xa8, 0xdf, 0x3e, 0x39, 0x78, 0x7e, 0xcf, 0xbf, 0x65, 0xb7, 0x9a, 0xac, 0x95, 0xf1, 0x80, 0x75, 0x6d, 0x00, 0xfd, 0xe8, 0xa8, 0x7d, 0xbc,
0x93, 0xd2, 0x34, 0xe5, 0x5b, 0x3b, 0xb6, 0x24, 0xd4, 0x2d, 0x9e, 0xb9, 0x2a, 0x0d, 0xad, 0x36, 0xf7, 0xfc, 0x9e, 0x27, 0xa5, 0xa9, 0x2a, 0x2a, 0x3d, 0x7e, 0xcd, 0x62, 0xb7, 0x79, 0xea, 0xb2,
0x2e, 0xae, 0x51, 0xcb, 0x99, 0xdc, 0x60, 0x19, 0xba, 0x3c, 0x40, 0x60, 0x2c, 0x13, 0x63, 0x99, 0x34, 0xb4, 0xda, 0x38, 0xbf, 0x46, 0x5d, 0xcf, 0x60, 0x4d, 0x69, 0xe8, 0x8a, 0x00, 0x91, 0xb1,
0x21, 0xeb, 0x5d, 0xee, 0x00, 0xa5, 0x64, 0x07, 0xf3, 0x6e, 0xa3, 0x12, 0x65, 0x60, 0x11, 0xf8, 0x4c, 0x8e, 0x21, 0x23, 0xd6, 0xbb, 0xc2, 0x81, 0x38, 0x66, 0x5b, 0x14, 0x77, 0x9b, 0x84, 0xb4,
0x1a, 0x5a, 0x31, 0x2f, 0x90, 0xdf, 0x2e, 0xdf, 0x2a, 0xd8, 0x0b, 0xd2, 0x73, 0x71, 0x2f, 0x57, 0x46, 0x16, 0x91, 0xaf, 0xa1, 0x95, 0xf3, 0x82, 0xf8, 0xed, 0x8a, 0x4a, 0xc0, 0x5f, 0xb0, 0x9e,
0xe7, 0xc0, 0xc4, 0x7d, 0xb2, 0x5b, 0xa0, 0x84, 0x01, 0x7b, 0xdc, 0x23, 0x38, 0x89, 0x11, 0x79, 0xf3, 0x7b, 0xb1, 0x3c, 0x43, 0x26, 0xee, 0xb3, 0xed, 0x82, 0x56, 0xe4, 0xb0, 0x27, 0x3c, 0xc2,
0x5a, 0x5a, 0xe3, 0x23, 0x06, 0xc8, 0x7e, 0x8f, 0x82, 0x8b, 0xa1, 0x15, 0x76, 0x51, 0x52, 0x46, 0x9b, 0x18, 0x99, 0xa7, 0xa5, 0x35, 0xde, 0x63, 0x80, 0xfc, 0xb7, 0x28, 0x98, 0x18, 0x5a, 0x69,
0x7a, 0xaa, 0x74, 0x9a, 0x0b, 0x9d, 0xcc, 0xd0, 0xd1, 0x3e, 0x6f, 0xe8, 0x9c, 0xcd, 0xd9, 0xc2, 0x17, 0x65, 0xcc, 0x59, 0x4f, 0x95, 0x4e, 0x72, 0xae, 0x93, 0x19, 0x19, 0xda, 0x15, 0x0d, 0x99,
0xea, 0x0f, 0x2a, 0x57, 0xf9, 0x04, 0x7d, 0xa2, 0xcd, 0x56, 0x07, 0x07, 0x57, 0xe5, 0xb9, 0x28, 0xd3, 0x39, 0x5d, 0x58, 0xfd, 0x41, 0xe5, 0x2a, 0x9f, 0x90, 0x4d, 0xd2, 0xa9, 0x64, 0x78, 0x71,
0x87, 0x52, 0xa6, 0x98, 0xd1, 0x3e, 0xdf, 0x2a, 0x9c, 0x87, 0x91, 0x4a, 0x66, 0x3e, 0xca, 0x4e, 0x55, 0x9e, 0xc9, 0x72, 0x08, 0x90, 0x52, 0x44, 0xbb, 0xa2, 0x12, 0x38, 0x0b, 0x23, 0x95, 0xcc,
0xf0, 0xb0, 0xd5, 0xb1, 0x17, 0xa1, 0xa5, 0x3d, 0xa9, 0x25, 0x3d, 0x25, 0x7b, 0xee, 0x02, 0x85, 0xbc, 0x97, 0xad, 0x60, 0xa1, 0x92, 0xf1, 0x17, 0xa1, 0xa4, 0x3d, 0xa9, 0x65, 0x7c, 0xc2, 0x76,
0xca, 0xdc, 0x6d, 0x54, 0xc6, 0xdb, 0xf1, 0x60, 0xc4, 0xde, 0x91, 0xc3, 0xc6, 0x0a, 0xed, 0x93, 0xdc, 0x03, 0x0a, 0x99, 0xb9, 0xdb, 0xc8, 0x8c, 0xd7, 0x13, 0x41, 0x89, 0xbf, 0x63, 0xfb, 0x8d,
0xb6, 0x48, 0x12, 0x7f, 0x29, 0x8e, 0xfc, 0xe6, 0xb0, 0x0d, 0x96, 0x6e, 0xae, 0x0c, 0x9b, 0x06, 0x9d, 0xf8, 0x88, 0xb5, 0x65, 0x92, 0xf8, 0x47, 0x71, 0xe0, 0x0f, 0x87, 0x63, 0xb8, 0x75, 0x73,
0x92, 0x7e, 0xca, 0x91, 0x00, 0xe0, 0x59, 0x94, 0xe5, 0x2a, 0xf5, 0x85, 0xf5, 0x08, 0x78, 0x86, 0x66, 0xf8, 0x34, 0x90, 0xf4, 0x53, 0x4e, 0x04, 0x20, 0xcf, 0xb2, 0x2c, 0x97, 0xa9, 0x4f, 0xac,
0xe2, 0xe8, 0x85, 0xbb, 0x4f, 0x6d, 0x1e, 0x20, 0x7d, 0x4a, 0x8e, 0xdc, 0xa9, 0x7e, 0x34, 0x2e, 0x47, 0xc8, 0x33, 0x26, 0x47, 0x2f, 0xdc, 0x7b, 0x6a, 0x8b, 0x00, 0xe3, 0xa7, 0xec, 0xc0, 0xdd,
0x45, 0xcf, 0xc9, 0x27, 0x5a, 0xf6, 0x98, 0x1c, 0xbc, 0x93, 0x39, 0x70, 0x74, 0x21, 0xf2, 0x09, 0xea, 0x47, 0xe3, 0x42, 0xf4, 0x9c, 0x7c, 0x22, 0xe5, 0x8f, 0xd9, 0xde, 0x3b, 0xc8, 0x91, 0xa3,
0xb4, 0x44, 0x26, 0xf2, 0x09, 0x86, 0xe9, 0x70, 0x94, 0xd9, 0x13, 0x30, 0xb1, 0x60, 0xf2, 0x72, 0x73, 0x99, 0x4f, 0xb0, 0x24, 0x32, 0x99, 0x4f, 0xc8, 0x4d, 0x47, 0xd0, 0x9a, 0x3f, 0x41, 0x15,
0x73, 0xb9, 0xfa, 0xb7, 0xb3, 0xb0, 0xef, 0x49, 0x6f, 0x28, 0x96, 0xb2, 0xb2, 0xa3, 0x64, 0xa7, 0x8b, 0x2a, 0x2f, 0xd7, 0x17, 0xcb, 0x7f, 0xbb, 0x0b, 0xff, 0x9e, 0xf5, 0x86, 0xf2, 0x1a, 0x36,
0x84, 0x5a, 0x38, 0x2b, 0x94, 0x6b, 0x7b, 0x5b, 0x8d, 0xbd, 0x8f, 0x48, 0x97, 0xcb, 0x22, 0xdb, 0x7a, 0x31, 0xdb, 0x2a, 0x31, 0x17, 0x4e, 0x8b, 0xd6, 0xb5, 0xb3, 0xad, 0xc6, 0xd9, 0x47, 0xac,
0x60, 0xad, 0x6e, 0xd8, 0xc8, 0xce, 0x09, 0xe5, 0xf2, 0xda, 0x37, 0x8e, 0xb4, 0x97, 0x55, 0xfa, 0x2b, 0xa0, 0xc8, 0xd6, 0x94, 0xab, 0x1b, 0x0e, 0xf2, 0x33, 0x16, 0x0b, 0xb8, 0xf2, 0x85, 0x03,
0x3a, 0x4b, 0x01, 0x84, 0x86, 0xf7, 0x10, 0x56, 0x72, 0xb9, 0xc2, 0x15, 0xdf, 0x80, 0x1e, 0xb2, 0xf6, 0x62, 0x13, 0xbe, 0xce, 0x52, 0x04, 0xa1, 0xe0, 0x3d, 0xc4, 0x9d, 0x1c, 0x96, 0xb4, 0xe3,
0x27, 0xe4, 0x90, 0xcb, 0xeb, 0x8f, 0x72, 0x15, 0x6a, 0x54, 0x55, 0x20, 0xaa, 0x57, 0xe0, 0x8a, 0x0b, 0xd0, 0x43, 0xfe, 0x84, 0xed, 0x0b, 0xb8, 0xfa, 0x08, 0xcb, 0x90, 0xa3, 0x4d, 0x06, 0xa2,
0xc4, 0x55, 0xc0, 0xda, 0x14, 0xbb, 0x50, 0x25, 0xce, 0x25, 0x98, 0x11, 0xa3, 0x75, 0xe8, 0x7a, 0x7a, 0x06, 0x2e, 0x59, 0x7f, 0xe3, 0xb0, 0xd6, 0xc5, 0xce, 0x55, 0x49, 0x7d, 0x09, 0x7b, 0xc4,
0x87, 0xc0, 0x13, 0xba, 0xc4, 0x90, 0x1d, 0xee, 0x00, 0x34, 0x66, 0xaa, 0x8c, 0xc4, 0xed, 0x58, 0x68, 0x15, 0xaa, 0xde, 0x21, 0xb4, 0x44, 0x26, 0xc9, 0x65, 0x47, 0x38, 0x80, 0x85, 0x99, 0x2a,
0x84, 0x0e, 0xdf, 0x2a, 0xd8, 0x39, 0xb9, 0x5f, 0xc5, 0x79, 0x3f, 0x2f, 0xb4, 0xb1, 0x97, 0xfe, 0x03, 0x74, 0x9c, 0x92, 0xd0, 0x11, 0x95, 0x80, 0x9f, 0xb1, 0xfb, 0x1b, 0x3f, 0xef, 0xe7, 0x85,
0xce, 0x7e, 0xe1, 0x6d, 0x66, 0x7f, 0x44, 0x35, 0x57, 0x43, 0x99, 0xa7, 0x23, 0x7d, 0x96, 0xa6, 0x36, 0xf6, 0xc2, 0xbf, 0xd9, 0x2f, 0x7c, 0xcd, 0xfc, 0xf7, 0xa8, 0x66, 0x6a, 0x08, 0x79, 0x3a,
0x46, 0x96, 0x25, 0x30, 0x0a, 0x47, 0x0c, 0x8c, 0x82, 0x4c, 0x8f, 0x48, 0xcb, 0x6a, 0xef, 0xa1, 0xd2, 0xa7, 0x69, 0x6a, 0xa0, 0x2c, 0x91, 0x51, 0xbc, 0x62, 0x60, 0x14, 0xd7, 0xf1, 0x01, 0x6b,
0x65, 0x75, 0x6d, 0x40, 0xb6, 0x1b, 0x03, 0x92, 0x92, 0x9d, 0x5c, 0x5b, 0x89, 0x37, 0xa6, 0xc7, 0x59, 0xed, 0x2d, 0xb4, 0xac, 0xae, 0x35, 0xc8, 0x76, 0xa3, 0x41, 0xc6, 0x6c, 0x2b, 0xd7, 0x16,
0x51, 0x86, 0xa3, 0xa9, 0x72, 0xa4, 0x67, 0x32, 0xc7, 0x41, 0xbb, 0xcf, 0x03, 0xa4, 0x7d, 0x72, 0xe8, 0xc5, 0xf4, 0x04, 0xad, 0xf1, 0x6a, 0xaa, 0x1c, 0xe9, 0x19, 0xe4, 0xd4, 0x68, 0x77, 0x45,
0x60, 0x41, 0x18, 0x6e, 0xe6, 0x63, 0x9d, 0xe1, 0xac, 0xed, 0xf2, 0xba, 0x8a, 0x7d, 0x43, 0x6e, 0x80, 0xf1, 0x11, 0xdb, 0xb3, 0xb8, 0x18, 0xae, 0xe7, 0x63, 0x9d, 0x51, 0xaf, 0xed, 0x8a, 0xba,
0xd5, 0x2b, 0xf9, 0x56, 0xd6, 0x67, 0x73, 0x54, 0x0f, 0xcd, 0x7e, 0x20, 0x77, 0xea, 0xa6, 0x17, 0x88, 0x7f, 0xc3, 0x6e, 0xd5, 0x33, 0xf9, 0x16, 0xea, 0xbd, 0x39, 0xaa, 0xbb, 0xe6, 0x3f, 0xb0,
0x8d, 0xa1, 0x15, 0xd5, 0x86, 0xd6, 0xcd, 0x84, 0x7c, 0x4d, 0xee, 0x55, 0xdb, 0x3f, 0x48, 0x33, 0x3b, 0x75, 0xd5, 0xf3, 0x46, 0xd3, 0x8a, 0x6a, 0x4d, 0xeb, 0x66, 0x42, 0xbe, 0x66, 0xf7, 0x36,
0x91, 0x2f, 0x45, 0x26, 0xf2, 0x44, 0xfa, 0xd4, 0xa3, 0x90, 0x3a, 0xfb, 0x2b, 0xc2, 0x40, 0x98, 0xc7, 0x3f, 0x80, 0x99, 0xc0, 0x4b, 0x99, 0xc9, 0x3c, 0x01, 0x1f, 0x7a, 0x14, 0x42, 0xe7, 0x7f,
0xc1, 0xa5, 0x91, 0xaf, 0x8c, 0x14, 0x56, 0xd2, 0xc7, 0xa4, 0x97, 0x80, 0xa4, 0xcd, 0xaf, 0xb5, 0x46, 0xe4, 0x88, 0x22, 0xb8, 0x30, 0xf0, 0xca, 0x80, 0xb4, 0x10, 0x3f, 0x66, 0xbd, 0x04, 0x57,
0x80, 0x07, 0x5e, 0x07, 0xd4, 0x22, 0x37, 0xf0, 0x04, 0xb8, 0xb0, 0x28, 0x43, 0x32, 0xa5, 0x4b, 0xda, 0xfc, 0x5a, 0x73, 0xb8, 0xe7, 0x65, 0x48, 0x2d, 0x71, 0x83, 0x5f, 0x80, 0x73, 0x4b, 0x6b,
0xde, 0x8d, 0x55, 0x8f, 0x70, 0x02, 0xe5, 0xd6, 0xe8, 0x74, 0xe1, 0x3a, 0xc1, 0xcd, 0xd6, 0x86, 0x0c, 0xa6, 0x74, 0xc1, 0xbb, 0xb6, 0xea, 0x11, 0x75, 0xa0, 0xdc, 0x1a, 0x9d, 0x2e, 0x5c, 0x25,
0x8e, 0x3e, 0x20, 0x44, 0xaf, 0x72, 0xe9, 0x03, 0x76, 0xdc, 0xf4, 0x45, 0xcd, 0x99, 0x4f, 0xd3, 0xb8, 0xde, 0xda, 0x90, 0xc5, 0x0f, 0x18, 0xd3, 0xcb, 0x1c, 0xbc, 0xc3, 0x8e, 0xeb, 0xbe, 0x24,
0x6a, 0x2b, 0x32, 0xff, 0x84, 0x39, 0x00, 0xda, 0xc2, 0xa8, 0x44, 0xe2, 0xf3, 0xd5, 0xe6, 0x0e, 0x39, 0xf5, 0x61, 0x5a, 0x6d, 0x65, 0xe6, 0xbf, 0x30, 0x07, 0x50, 0x5a, 0x18, 0x95, 0x00, 0x7d,
0x30, 0x43, 0xee, 0x86, 0x94, 0xde, 0xaa, 0x5c, 0x95, 0x53, 0x9f, 0xd5, 0x57, 0xe4, 0xf0, 0x0a, 0x5f, 0x6d, 0xe1, 0x00, 0x37, 0xec, 0x6e, 0x08, 0xe9, 0xad, 0xca, 0x55, 0x39, 0xf5, 0x51, 0x7d,
0xb1, 0x6c, 0xa4, 0xd5, 0x0b, 0xca, 0x33, 0xff, 0xf0, 0xf9, 0x1c, 0x5a, 0x8d, 0x1c, 0x9a, 0xe7, 0xc5, 0xf6, 0x2f, 0x09, 0x43, 0x23, 0xac, 0x5e, 0x10, 0x9e, 0xfa, 0x8f, 0xcf, 0xc7, 0xd0, 0x6a,
0x6b, 0x7f, 0x72, 0x3e, 0x56, 0x6c, 0x63, 0x72, 0xb9, 0xd4, 0xb3, 0x1a, 0x93, 0x06, 0x71, 0x93, 0xc4, 0xd0, 0xbc, 0x5f, 0xfb, 0x93, 0xfb, 0xf1, 0xa2, 0xf2, 0x29, 0xe0, 0x5a, 0xcf, 0x6a, 0x4c,
0x49, 0xaf, 0xfb, 0x2f, 0x11, 0x25, 0x36, 0xd3, 0x07, 0x9d, 0xaa, 0xab, 0xcd, 0x2b, 0x9d, 0x5f, 0x1a, 0xc2, 0x4d, 0x26, 0xbd, 0xec, 0xbf, 0x78, 0x04, 0x2a, 0xa6, 0x0f, 0x3a, 0x55, 0x97, 0xeb,
0xa9, 0x09, 0xbd, 0x4d, 0xda, 0xdb, 0x2b, 0x03, 0x22, 0x94, 0x5b, 0x17, 0xa1, 0xd3, 0x75, 0x01, 0x57, 0x3a, 0xbf, 0x54, 0x93, 0xf8, 0x36, 0x6b, 0x57, 0x4f, 0x06, 0x97, 0x98, 0x6e, 0x5d, 0x84,
0x84, 0x2d, 0x45, 0xb6, 0x90, 0xde, 0x9d, 0x03, 0xf0, 0x11, 0x98, 0x83, 0x1f, 0x25, 0x8d, 0xaf, 0x4a, 0xd7, 0x05, 0x12, 0x76, 0x2d, 0xb3, 0x05, 0x78, 0x73, 0x0e, 0xe0, 0x20, 0x30, 0x47, 0x3b,
0x4d, 0x85, 0xd9, 0x6f, 0x11, 0xe9, 0x71, 0x79, 0x3d, 0x54, 0x93, 0x9c, 0x8b, 0xd5, 0x68, 0x7d, 0x0a, 0x8c, 0xcf, 0xcd, 0x06, 0xf3, 0xbf, 0x22, 0xd6, 0x13, 0x70, 0x35, 0x54, 0x93, 0x5c, 0xc8,
0x63, 0x13, 0xd6, 0xee, 0x6b, 0xeb, 0xb3, 0xfb, 0x6a, 0xd7, 0xe7, 0x72, 0x1d, 0x02, 0x22, 0x80, 0xe5, 0x68, 0x75, 0x63, 0x11, 0xd6, 0xde, 0x6b, 0xeb, 0xb3, 0xf7, 0x6a, 0x57, 0x67, 0xb0, 0x0a,
0x94, 0xe5, 0xba, 0x50, 0x46, 0xfa, 0x70, 0x1e, 0x6d, 0x7f, 0x37, 0x1d, 0x37, 0x45, 0xdc, 0xef, 0x0e, 0x09, 0x60, 0xc8, 0xb0, 0x2a, 0x94, 0x01, 0xef, 0xce, 0xa3, 0x6a, 0xba, 0xe9, 0xb8, 0x2e,
0x06, 0x6b, 0x0f, 0x17, 0x6e, 0xcf, 0xfb, 0x00, 0xc0, 0x9e, 0x92, 0x23, 0x37, 0x37, 0xab, 0x93, 0xe2, 0xa6, 0x1b, 0xca, 0x3d, 0x3e, 0xb8, 0x1d, 0x6f, 0x83, 0x9e, 0xdb, 0x6d, 0xd6, 0xbe, 0x04,
0x55, 0xb1, 0xa2, 0x5a, 0x2c, 0x36, 0x46, 0x3b, 0x6d, 0xec, 0x1b, 0x63, 0xde, 0x2c, 0x65, 0x6e, 0xa0, 0xf1, 0xa4, 0x2d, 0x70, 0x89, 0xdd, 0x26, 0x87, 0xe5, 0x9b, 0x15, 0x24, 0x60, 0x68, 0x34,
0xe1, 0x0f, 0x03, 0x63, 0x60, 0xae, 0xd3, 0x45, 0x26, 0xbd, 0x71, 0x4d, 0x03, 0x74, 0x58, 0xed, 0xe9, 0x89, 0x4a, 0xe0, 0x77, 0x5d, 0x63, 0xa0, 0xd9, 0xa4, 0x2b, 0x2a, 0x01, 0x7f, 0xca, 0x0e,
0x57, 0x5d, 0x3a, 0x15, 0x86, 0x18, 0xd2, 0x18, 0x1d, 0xea, 0xe1, 0x00, 0xfb, 0x1f, 0xe9, 0xbc, 0x5c, 0x17, 0xde, 0xc4, 0xb9, 0xb9, 0x79, 0x54, 0xbb, 0x39, 0x1f, 0x93, 0x9e, 0x36, 0xf6, 0x8d,
0xcf, 0xed, 0xe0, 0x39, 0x90, 0x93, 0x0a, 0x2b, 0xc2, 0x1b, 0x02, 0x32, 0xfb, 0x3b, 0xc2, 0xde, 0x31, 0x6f, 0xae, 0x21, 0xb7, 0x38, 0x11, 0x61, 0x53, 0x99, 0xeb, 0x74, 0x91, 0x81, 0x57, 0xae,
0x70, 0x0d, 0x51, 0x9b, 0xa7, 0xf8, 0xdf, 0x80, 0x54, 0xf0, 0x1e, 0x45, 0xfe, 0xbf, 0x11, 0x14, 0x49, 0x90, 0x5c, 0xab, 0xfd, 0xae, 0x23, 0x67, 0x83, 0xd1, 0x07, 0x18, 0xa3, 0x43, 0x76, 0x1d,
0xe0, 0x0a, 0xde, 0x4c, 0x3f, 0x50, 0x51, 0xfe, 0xa2, 0x41, 0x15, 0x06, 0x5f, 0xe7, 0xb3, 0xc1, 0xe0, 0xff, 0x63, 0x9d, 0xf7, 0xb9, 0x1d, 0x3c, 0x47, 0xaa, 0x53, 0x69, 0x65, 0xf8, 0x91, 0x70,
0xb7, 0x5b, 0x0d, 0xbe, 0x87, 0x84, 0x14, 0x8b, 0xf1, 0x4c, 0x6e, 0x0a, 0xa1, 0x0c, 0x7e, 0xd8, 0xcd, 0xff, 0x8e, 0xa8, 0xd2, 0x5c, 0x79, 0xd5, 0xba, 0x33, 0x4d, 0x2f, 0x48, 0x0c, 0xbd, 0xca,
0xba, 0xbc, 0xa6, 0xc1, 0xc6, 0x50, 0x6b, 0x37, 0xd8, 0x0f, 0xf0, 0x1c, 0x15, 0xae, 0xd5, 0xb0, 0xc8, 0x4f, 0x2f, 0x41, 0x80, 0xa6, 0xf0, 0x07, 0xf6, 0xed, 0x99, 0xd6, 0x5f, 0xd4, 0xf6, 0x42,
0xe7, 0xce, 0xe2, 0x10, 0xfb, 0x0e, 0xf8, 0xbe, 0xf6, 0x2f, 0x0c, 0xbe, 0x19, 0xf0, 0x1e, 0x2b, 0x1b, 0xed, 0x7c, 0xd6, 0x46, 0xb7, 0x37, 0x6d, 0xf4, 0x21, 0x63, 0xc5, 0x62, 0x3c, 0x83, 0x75,
0x3b, 0xd5, 0x0b, 0xeb, 0xa7, 0x90, 0xff, 0xe8, 0x7c, 0xa2, 0x7d, 0xf9, 0xe8, 0x97, 0x07, 0x13, 0x21, 0x55, 0xa0, 0xb8, 0x26, 0xa1, 0x32, 0x53, 0x2b, 0xf7, 0x4d, 0xec, 0xd1, 0x3d, 0x36, 0xb8,
0x65, 0xa7, 0x8b, 0xf1, 0x69, 0xa2, 0xe7, 0xcf, 0x06, 0x83, 0x24, 0x7f, 0x86, 0xdf, 0xf2, 0xc1, 0x56, 0x11, 0x3d, 0x77, 0x17, 0x87, 0xf8, 0x77, 0xc8, 0xf7, 0x95, 0xff, 0xaf, 0xe8, 0x07, 0xc2,
0xe0, 0x19, 0xfe, 0x1e, 0xc6, 0xbb, 0xf8, 0x01, 0x1f, 0xfc, 0x13, 0x00, 0x00, 0xff, 0xff, 0xe6, 0xdf, 0x5d, 0xd9, 0xa9, 0x5e, 0x58, 0xdf, 0xd3, 0xfc, 0xd8, 0xf4, 0x89, 0xf4, 0xe5, 0xa3, 0x5f,
0x69, 0x17, 0x4b, 0xdb, 0x0b, 0x00, 0x00, 0x1e, 0x4c, 0x94, 0x9d, 0x2e, 0xc6, 0x27, 0x89, 0x9e, 0x3f, 0x1b, 0x0c, 0x92, 0xfc, 0x19, 0x0d,
0xf9, 0x83, 0xc1, 0x33, 0x9a, 0x45, 0xc6, 0xdb, 0x34, 0xce, 0x0f, 0xfe, 0x09, 0x00, 0x00, 0xff,
0xff, 0xab, 0x59, 0x52, 0xd8, 0x29, 0x0c, 0x00, 0x00,
} }
...@@ -20,7 +20,15 @@ var TestPrivkeyHex = []string{ ...@@ -20,7 +20,15 @@ var TestPrivkeyHex = []string{
"2116459C0EC8ED01AA0EEAE35CAC5C96F94473F7816F114873291217303F6989", "2116459C0EC8ED01AA0EEAE35CAC5C96F94473F7816F114873291217303F6989",
} }
//TestPrivkeyList : /*
TestPrivkeyList : crypto.PrivKey list
addr:12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv
addr:14KEKbYtKKQm4wMthSK9J4La4nAiidGozt
addr:1EbDHAXpoiewjPLX9uqoz38HsKqMXayZrF
addr:1PUiGcbsccfxW3zuvHXZBJfznziph5miAo
addr:1KcCVZLSQYRUwE5EXTsAoQs9LuJW6xwfQa
addr:1EDnnePAZN48aC2hiTDzhkczfF39g1pZZX
*/
var TestPrivkeyList = []crypto.PrivKey{ var TestPrivkeyList = []crypto.PrivKey{
HexToPrivkey("4257D8692EF7FE13C68B65D6A52F03933DB2FA5CE8FAF210B5B8B80C721CED01"), HexToPrivkey("4257D8692EF7FE13C68B65D6A52F03933DB2FA5CE8FAF210B5B8B80C721CED01"),
HexToPrivkey("CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944"), HexToPrivkey("CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944"),
......
...@@ -11,9 +11,6 @@ import ( ...@@ -11,9 +11,6 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"errors"
"strconv"
"github.com/33cn/chain33/account" "github.com/33cn/chain33/account"
"github.com/33cn/chain33/common" "github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address" "github.com/33cn/chain33/common/address"
...@@ -26,39 +23,6 @@ import ( ...@@ -26,39 +23,6 @@ import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
) )
func (wallet *Wallet) parseExpire(expire string) (int64, error) {
if len(expire) == 0 {
return 0, errors.New("Expire string should not be empty")
}
if expire[0] == 'H' && expire[1] == ':' {
txHeight, err := strconv.ParseInt(expire[2:], 10, 64)
if err != nil {
return 0, err
}
if txHeight <= 0 {
//fmt.Printf("txHeight should be grate to 0")
return 0, errors.New("txHeight should be grate to 0")
}
if txHeight+types.TxHeightFlag < txHeight {
return 0, errors.New("txHeight overflow")
}
return txHeight + types.TxHeightFlag, nil
}
blockHeight, err := strconv.ParseInt(expire, 10, 64)
if err == nil {
return blockHeight, nil
}
expireTime, err := time.ParseDuration(expire)
if err == nil {
return int64(expireTime), nil
}
return 0, err
}
// ProcSignRawTx 用钱包对交易进行签名 // ProcSignRawTx 用钱包对交易进行签名
//input: //input:
//type ReqSignRawTx struct { //type ReqSignRawTx struct {
...@@ -115,7 +79,18 @@ func (wallet *Wallet) ProcSignRawTx(unsigned *types.ReqSignRawTx) (string, error ...@@ -115,7 +79,18 @@ func (wallet *Wallet) ProcSignRawTx(unsigned *types.ReqSignRawTx) (string, error
if err != nil { if err != nil {
return "", err return "", err
} }
expire, err := wallet.parseExpire(unsigned.GetExpire())
if unsigned.GetNewExecer() != nil {
tx.Execer = unsigned.NewExecer
}
if unsigned.NewToAddr != "" {
tx.To = unsigned.NewToAddr
}
if unsigned.Fee != 0 {
tx.Fee = unsigned.Fee
}
expire, err := types.ParseExpire(unsigned.GetExpire())
if err != nil { if err != nil {
return "", err return "", err
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment