Commit 112b9f75 authored by lilinleeli1234's avatar lilinleeli1234

Merge branch 'master' of https://github.com/lynAzrael/plugin

parents 5bace73a b7699804
all:
chmod +x ./build.sh
./build.sh $(OUT) $(FLAG)
\ No newline at end of file
#!/bin/sh
strpwd=$(pwd)
strcmd=${strpwd##*dapp/}
strapp=${strcmd%/cmd*}
OUT_DIR="${1}/$strapp"
#FLAG=$2
mkdir -p "${OUT_DIR}"
cp ./build/* "${OUT_DIR}"
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// 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 cmd package command
import ( import (
"fmt" "fmt"
......
...@@ -2,12 +2,12 @@ package js ...@@ -2,12 +2,12 @@ package js
import ( import (
"github.com/33cn/chain33/pluginmgr" "github.com/33cn/chain33/pluginmgr"
"github.com/33cn/plugin/plugin/dapp/js/cmd"
"github.com/33cn/plugin/plugin/dapp/js/executor" "github.com/33cn/plugin/plugin/dapp/js/executor"
ptypes "github.com/33cn/plugin/plugin/dapp/js/types" ptypes "github.com/33cn/plugin/plugin/dapp/js/types"
// init auto test // init auto test
_ "github.com/33cn/plugin/plugin/dapp/js/autotest" _ "github.com/33cn/plugin/plugin/dapp/js/autotest"
"github.com/33cn/plugin/plugin/dapp/js/command"
) )
func init() { func init() {
...@@ -15,7 +15,7 @@ func init() { ...@@ -15,7 +15,7 @@ func init() {
Name: ptypes.JsX, Name: ptypes.JsX,
ExecName: executor.GetName(), ExecName: executor.GetName(),
Exec: executor.Init, Exec: executor.Init,
Cmd: cmd.JavaScriptCmd, Cmd: command.JavaScriptCmd,
RPC: nil, RPC: nil,
}) })
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package executor package executor
import ( import (
"fmt"
"sort" "sort"
log "github.com/33cn/chain33/common/log/log15" log "github.com/33cn/chain33/common/log/log15"
...@@ -61,25 +62,31 @@ func (lott *Lottery) GetDriverName() string { ...@@ -61,25 +62,31 @@ func (lott *Lottery) GetDriverName() string {
return pty.LotteryX return pty.LotteryX
} }
func (lott *Lottery) findLotteryBuyRecords(key []byte) (*pty.LotteryBuyRecords, error) { func (lott *Lottery) findLotteryBuyRecords(prefix []byte) (*pty.LotteryBuyRecords, error) {
count := 0
count := lott.GetLocalDB().PrefixCount(key) var key []byte
llog.Error("findLotteryBuyRecords", "count", count)
values, err := lott.GetLocalDB().List(key, nil, int32(count), 0)
if err != nil {
return nil, err
}
var records pty.LotteryBuyRecords var records pty.LotteryBuyRecords
for _, value := range values { for {
var record pty.LotteryBuyRecord values, err := lott.GetLocalDB().List(prefix, key, DefultCount, 0)
err := types.Decode(value, &record)
if err != nil { if err != nil {
continue return nil, err
}
for _, value := range values {
var record pty.LotteryBuyRecord
err := types.Decode(value, &record)
if err != nil {
continue
}
records.Records = append(records.Records, &record)
}
count += len(values)
if len(values) < int(DefultCount) {
break
} }
records.Records = append(records.Records, &record) key = []byte(fmt.Sprintf("%s:%18d", prefix, records.Records[count-1].Index))
} }
llog.Info("findLotteryBuyRecords", "count", count)
return &records, nil return &records, nil
} }
......
...@@ -94,7 +94,7 @@ func (a *action) MultiSigAccCreate(accountCreate *mty.MultiSigAccCreate) (*types ...@@ -94,7 +94,7 @@ func (a *action) MultiSigAccCreate(accountCreate *mty.MultiSigAccCreate) (*types
//通过创建交易的txhash生成一个唯一的多重签名合约 NewAddrFromString //通过创建交易的txhash生成一个唯一的多重签名合约 NewAddrFromString
addr := address.MultiSignAddress(a.txhash) addr := address.MultiSignAddress(a.txhash)
//账户去重校验 //账户去重校验
multiSig, err := getMultiSigAccount(a.localdb, addr) multiSig, err := getMultiSigAccFromDb(a.db, addr)
if err == nil && multiSig != nil { if err == nil && multiSig != nil {
return nil, mty.ErrAccountHasExist return nil, mty.ErrAccountHasExist
} }
......
...@@ -36,13 +36,11 @@ asset-transfer 分两种, 主链转出, 主链转入 ...@@ -36,13 +36,11 @@ asset-transfer 分两种, 主链转出, 主链转入
1. 用户主链paracross合约帐号, balance - 1. 用户主链paracross合约帐号, balance -
1. 某平行链paracross合约帐号, balance + 1. 某平行链paracross合约帐号, balance +
* 平行链(如果上面步骤失败,, 平行链会过滤掉这个交易) * 平行链(如果上面步骤失败,, 平行链会过滤掉这个交易)
1. 平行链中paracross合约帐号 balance +
1. 平行链中 用户paracross合约帐号 balance + 1. 平行链中 用户paracross合约帐号 balance +
主链转入 withdraw 主链转入 withdraw
* 平行链 * 平行链
1. 平行链中 用户paracross合约帐号 balance - 1. 平行链中 用户paracross合约帐号 balance -
1. 平行链中paracross合约帐号 balance -
* 主链(上面步骤失败, 不进行操作) * 主链(上面步骤失败, 不进行操作)
1. commit 交易共识时执行 1. commit 交易共识时执行
1. 某平行链paracross合约帐号, balance - 1. 某平行链paracross合约帐号, balance -
......
...@@ -51,11 +51,17 @@ func (*signatureMock) Equals(crypto.Signature) bool { ...@@ -51,11 +51,17 @@ func (*signatureMock) Equals(crypto.Signature) bool {
return true return true
} }
func formatByte32(b []byte) []byte {
var b32 [32]byte
copy(b32[:], b)
return b32[:]
}
type privKeyMock struct { type privKeyMock struct {
} }
func (mock *privKeyMock) Bytes() []byte { func (mock *privKeyMock) Bytes() []byte {
return []byte("1234") return formatByte32([]byte("1234"))
} }
func (mock *privKeyMock) Sign(msg []byte) crypto.Signature { func (mock *privKeyMock) Sign(msg []byte) crypto.Signature {
...@@ -82,7 +88,7 @@ func TestNewPrivacy(t *testing.T) { ...@@ -82,7 +88,7 @@ func TestNewPrivacy(t *testing.T) {
} }
func test_RecoverOnetimePriKey(t *testing.T) { func test_RecoverOnetimePriKey(t *testing.T) {
R := []byte("1234") R := formatByte32([]byte("1234"))
pkm := privKeyMock{} pkm := privKeyMock{}
privKey, err := RecoverOnetimePriKey(R, &pkm, &pkm, 0) privKey, err := RecoverOnetimePriKey(R, &pkm, &pkm, 0)
assert.Nil(t, err) assert.Nil(t, err)
......
#!/usr/bin/env bash #!/usr/bin/env bash
strpwd=$(pwd) #strpwd=$(pwd)
strcmd=${strpwd##*dapp/} #strcmd=${strpwd##*dapp/}
strapp=${strcmd%/cmd*} #strapp=${strcmd%/cmd*}
#
#OUT_DIR="${1}/$strapp"
#SRC_RELAYD=github.com/33cn/plugin/plugin/dapp/relay/cmd/relayd
#FLAG=$2
OUT_DIR="${1}/$strapp" # shellcheck disable=SC2086,1072
SRC_RELAYD=github.com/33cn/plugin/plugin/dapp/relay/cmd/relayd #go build -i ${FLAG} -v -o "${OUT_DIR}/relayd" "${SRC_RELAYD}"
FLAG=$2 #cp ./relayd/relayd.toml "${OUT_DIR}/relayd.toml"
#cp ./build/* "${OUT_DIR}"
# shellcheck disable=SC2086 echo "ignore"
go build -i ${FLAG} -v -o "${OUT_DIR}/relayd" "${SRC_RELAYD}"
cp ./relayd/relayd.toml "${OUT_DIR}/relayd.toml"
cp ./build/* "${OUT_DIR}"
...@@ -170,6 +170,7 @@ function relay_test() { ...@@ -170,6 +170,7 @@ function relay_test() {
coinaddr=$(${1} tx query -s "${buy_hash}" | jq -r ".receipt.logs[2].log.coinAddr") coinaddr=$(${1} tx query -s "${buy_hash}" | jq -r ".receipt.logs[2].log.coinAddr")
if [ "${coinaddr}" != "1Am9UTGfdnxabvcywYG2hvzr6qK8T3oUZT" ]; then if [ "${coinaddr}" != "1Am9UTGfdnxabvcywYG2hvzr6qK8T3oUZT" ]; then
${1} tx query -s "${buy_hash}"
echo "wrong create order to coinaddr" echo "wrong create order to coinaddr"
exit 1 exit 1
fi fi
......
...@@ -18,6 +18,8 @@ type tokenAutoTest struct { ...@@ -18,6 +18,8 @@ type tokenAutoTest struct {
TransferCaseArr []autotest.TransferCase `toml:"TransferCase,omitempty"` TransferCaseArr []autotest.TransferCase `toml:"TransferCase,omitempty"`
WithdrawCaseArr []autotest.WithdrawCase `toml:"WithdrawCase,omitempty"` WithdrawCaseArr []autotest.WithdrawCase `toml:"WithdrawCase,omitempty"`
TokenRevokeCaseArr []TokenRevokeCase `toml:"TokenRevokeCase,omitempty"` TokenRevokeCaseArr []TokenRevokeCase `toml:"TokenRevokeCase,omitempty"`
TokenMintCaseArr []TokenMintCase `toml:"TokenMintCase,omitempty"`
TokenBurnCaseArr []TokenBurnCase `toml:"TokenBurnCase,omitempty"`
} }
func init() { func init() {
......
...@@ -7,7 +7,7 @@ command = "account import_key -k 0xc21d38be90493512a5c2417d565269a8b23ce8152010e ...@@ -7,7 +7,7 @@ command = "account import_key -k 0xc21d38be90493512a5c2417d565269a8b23ce8152010e
[[TokenPreCreateCase]] [[TokenPreCreateCase]]
id = "tokenPre" id = "tokenPre"
command = "send token precreate -f 0.01 -i testToken -n testToken -s TC -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t 100000 -p 1 -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv" command = "send token precreate -c 1 -f 0.01 -i testToken -n testToken -s TC -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t 100000 -p 1 -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"
dep = ["transForPrecreate", "import1"] dep = ["transForPrecreate", "import1"]
[[TokenPreCreateCase]] [[TokenPreCreateCase]]
...@@ -21,6 +21,19 @@ id = "tokenFinish" ...@@ -21,6 +21,19 @@ id = "tokenFinish"
command = "send token finish -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -f 0.01 -s TC -k 0xc34b5d9d44ac7b754806f761d3d4d2c4fe5214f6b074c19f069c4f5c2a29c8cc" command = "send token finish -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -f 0.01 -s TC -k 0xc34b5d9d44ac7b754806f761d3d4d2c4fe5214f6b074c19f069c4f5c2a29c8cc"
dep = ["tokenPre"] dep = ["tokenPre"]
[[TokenMintCase]]
id = "tokenMint"
command = "send token mint -a 100 -s TC -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"
dep = ["tokenFinish"]
amount = "100"
checkItem = ["balance"]
[[TokenBurnCase]]
id = "tokenBurn"
command = "send token burn -a 50 -s TC -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"
dep = ["tokenMint"]
amount = "50"
checkItem = ["balance"]
#send to token for precreate #send to token for precreate
[[TransferCase]] [[TransferCase]]
......
...@@ -6,6 +6,8 @@ package autotest ...@@ -6,6 +6,8 @@ package autotest
import ( import (
"github.com/33cn/chain33/cmd/autotest/types" "github.com/33cn/chain33/cmd/autotest/types"
"strconv"
) )
// TokenPreCreateCase token precreatecase command // TokenPreCreateCase token precreatecase command
...@@ -59,3 +61,109 @@ func (testCase *TokenFinishCreateCase) SendCommand(packID string) (types.PackFun ...@@ -59,3 +61,109 @@ func (testCase *TokenFinishCreateCase) SendCommand(packID string) (types.PackFun
return types.DefaultSend(testCase, &TokenFinishCreatePack{}, packID) return types.DefaultSend(testCase, &TokenFinishCreatePack{}, packID)
} }
// TokenMintCase token mint case
type TokenMintCase struct {
types.BaseCase
Amount string `toml:"amount"`
}
// TokenMintPack token mint pack command
type TokenMintPack struct {
types.BaseCasePack
}
// SendCommand send command function of tokenfinishcreatecase
func (testCase *TokenMintCase) SendCommand(packID string) (types.PackFunc, error) {
return types.DefaultSend(testCase, &TokenMintPack{}, packID)
}
// GetCheckHandlerMap get check handle for map
func (pack *TokenMintPack) GetCheckHandlerMap() interface{} {
funcMap := make(types.CheckHandlerMapDiscard, 2)
funcMap["balance"] = pack.checkBalance
return funcMap
}
func (pack *TokenMintPack) checkBalance(txInfo map[string]interface{}) bool {
logArr := txInfo["receipt"].(map[string]interface{})["logs"].([]interface{})
logTokenBurn := logArr[1].(map[string]interface{})["log"].(map[string]interface{})
logAccBurn := logArr[2].(map[string]interface{})["log"].(map[string]interface{})
interCase := pack.TCase.(*TokenMintCase)
amount1, _ := strconv.ParseInt(interCase.Amount, 10, 64)
amount := amount1 * 1e8
pack.FLog.Info("MintDetails", "TestID", pack.PackID,
"TokenPrev", logTokenBurn["prev"].(map[string]interface{})["total"].(string),
"TokenCurr", logTokenBurn["current"].(map[string]interface{})["total"].(string),
"AccPrev", logAccBurn["prev"].(map[string]interface{})["balance"].(string),
"AccCurr", logAccBurn["current"].(map[string]interface{})["balance"].(string),
"amount", amount1)
totalCurrent := parseInt64(logTokenBurn["current"].(map[string]interface{})["total"])
totalPrev := parseInt64(logTokenBurn["prev"].(map[string]interface{})["total"])
accCurrent := parseInt64(logAccBurn["current"].(map[string]interface{})["balance"])
accPrev := parseInt64(logAccBurn["prev"].(map[string]interface{})["balance"])
return totalCurrent-amount == totalPrev && accCurrent-amount == accPrev
}
// TokenBurnCase token mint case
type TokenBurnCase struct {
types.BaseCase
Amount string `toml:"amount"`
}
// TokenBurnPack token mint pack command
type TokenBurnPack struct {
types.BaseCasePack
}
// SendCommand send command function
func (testCase *TokenBurnCase) SendCommand(packID string) (types.PackFunc, error) {
return types.DefaultSend(testCase, &TokenBurnPack{}, packID)
}
// GetCheckHandlerMap get check handle for map
func (pack *TokenBurnPack) GetCheckHandlerMap() interface{} {
funcMap := make(types.CheckHandlerMapDiscard, 2)
funcMap["balance"] = pack.checkBalance
return funcMap
}
func (pack *TokenBurnPack) checkBalance(txInfo map[string]interface{}) bool {
logArr := txInfo["receipt"].(map[string]interface{})["logs"].([]interface{})
logTokenBurn := logArr[1].(map[string]interface{})["log"].(map[string]interface{})
logAccBurn := logArr[2].(map[string]interface{})["log"].(map[string]interface{})
interCase := pack.TCase.(*TokenBurnCase)
amount1, _ := strconv.ParseInt(interCase.Amount, 10, 64)
amount := amount1 * 1e8
pack.FLog.Info("BurnDetails", "TestID", pack.PackID,
"TokenPrev", logTokenBurn["prev"].(map[string]interface{})["total"].(string),
"TokenCurr", logTokenBurn["current"].(map[string]interface{})["total"].(string),
"AccPrev", logAccBurn["prev"].(map[string]interface{})["balance"].(string),
"AccCurr", logAccBurn["current"].(map[string]interface{})["balance"].(string),
"amount", amount1)
totalCurrent := parseInt64(logTokenBurn["current"].(map[string]interface{})["total"])
totalPrev := parseInt64(logTokenBurn["prev"].(map[string]interface{})["total"])
accCurrent := parseInt64(logAccBurn["current"].(map[string]interface{})["balance"])
accPrev := parseInt64(logAccBurn["prev"].(map[string]interface{})["balance"])
return totalCurrent+amount == totalPrev && accCurrent+amount == accPrev
}
func parseInt64(s interface{}) int64 {
i, _ := strconv.ParseInt(s.(string), 10, 64)
return i
}
...@@ -42,6 +42,9 @@ func TokenCmd() *cobra.Command { ...@@ -42,6 +42,9 @@ func TokenCmd() *cobra.Command {
CreateRawTokenFinishTxCmd(), CreateRawTokenFinishTxCmd(),
CreateRawTokenRevokeTxCmd(), CreateRawTokenRevokeTxCmd(),
CreateTokenTransferExecCmd(), CreateTokenTransferExecCmd(),
CreateRawTokenMintTxCmd(),
CreateRawTokenBurnTxCmd(),
GetTokenLogsCmd(),
) )
return cmd return cmd
...@@ -465,3 +468,118 @@ func tokenRevoke(cmd *cobra.Command, args []string) { ...@@ -465,3 +468,118 @@ func tokenRevoke(cmd *cobra.Command, args []string) {
ctx := jsonclient.NewRPCCtx(rpcLaddr, "token.CreateRawTokenRevokeTx", params, nil) ctx := jsonclient.NewRPCCtx(rpcLaddr, "token.CreateRawTokenRevokeTx", params, nil)
ctx.RunWithoutMarshal() ctx.RunWithoutMarshal()
} }
// CreateRawTokenMintTxCmd create raw token mintage transaction
func CreateRawTokenMintTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "mint",
Short: "Create a mint token transaction",
Run: tokenMint,
}
addTokenMintFlags(cmd)
return cmd
}
func addTokenMintFlags(cmd *cobra.Command) {
cmd.Flags().StringP("symbol", "s", "", "token symbol")
cmd.MarkFlagRequired("symbol")
cmd.Flags().Float64P("amount", "a", 0, "amount of mintage")
cmd.MarkFlagRequired("amount")
cmd.Flags().Float64P("fee", "f", 0, "token transaction fee")
}
func tokenMint(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
symbol, _ := cmd.Flags().GetString("symbol")
amount, _ := cmd.Flags().GetFloat64("amount")
params := &tokenty.TokenMint{
Symbol: symbol,
Amount: int64((amount+0.000001)*1e4) * 1e4,
}
ctx := jsonclient.NewRPCCtx(rpcLaddr, "token.CreateRawTokenMintTx", params, nil)
ctx.RunWithoutMarshal()
}
// CreateRawTokenBurnTxCmd create raw token burn transaction
func CreateRawTokenBurnTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "burn",
Short: "Create a burn token transaction",
Run: tokenBurn,
}
addTokenBurnFlags(cmd)
return cmd
}
func addTokenBurnFlags(cmd *cobra.Command) {
cmd.Flags().StringP("symbol", "s", "", "token symbol")
cmd.MarkFlagRequired("symbol")
cmd.Flags().Float64P("amount", "a", 0, "amount of burn")
cmd.MarkFlagRequired("amount")
cmd.Flags().Float64P("fee", "f", 0, "token transaction fee")
}
func tokenBurn(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
symbol, _ := cmd.Flags().GetString("symbol")
amount, _ := cmd.Flags().GetFloat64("amount")
params := &tokenty.TokenBurn{
Symbol: symbol,
Amount: int64((amount+0.000001)*1e4) * 1e4,
}
ctx := jsonclient.NewRPCCtx(rpcLaddr, "token.CreateRawTokenBurnTx", params, nil)
ctx.RunWithoutMarshal()
}
// GetTokenLogsCmd get logs of token
func GetTokenLogsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "get_token_logs",
Short: "Get logs of token",
Run: getTokenLogs,
}
getTokenLogsFlags(cmd)
return cmd
}
func getTokenLogs(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
paraName, _ := cmd.Flags().GetString("paraName")
symbol, _ := cmd.Flags().GetString("symbol")
var params rpctypes.Query4Jrpc
params.Execer = getRealExecName(paraName, "token")
params.FuncName = "GetTokenHistory"
params.Payload = types.MustPBToJSON(&types.ReqString{Data: symbol})
rpc, err := jsonclient.NewJSONClient(rpcLaddr)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
var res tokenty.ReplyTokenLogs
err = rpc.Call("Chain33.Query", params, &res)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
data, err := json.MarshalIndent(res, "", " ")
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
fmt.Println(string(data))
}
func getTokenLogsFlags(cmd *cobra.Command) {
cmd.Flags().StringP("symbol", "s", "", "token symbol")
cmd.MarkFlagRequired("symbol")
}
...@@ -69,3 +69,13 @@ func (t *token) Exec_TransferToExec(payload *types.AssetsTransferToExec, tx *typ ...@@ -69,3 +69,13 @@ func (t *token) Exec_TransferToExec(payload *types.AssetsTransferToExec, tx *typ
} }
return t.ExecTransWithdraw(db, tx, &tokenAction, index) return t.ExecTransWithdraw(db, tx, &tokenAction, index)
} }
func (t *token) Exec_TokenMint(payload *tokenty.TokenMint, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newTokenAction(t, "", tx)
return action.mint(payload)
}
func (t *token) Exec_TokenBurn(payload *tokenty.TokenBurn, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newTokenAction(t, "", tx)
return action.burn(payload)
}
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package executor package executor
import ( import (
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
tokenty "github.com/33cn/plugin/plugin/dapp/token/types" tokenty "github.com/33cn/plugin/plugin/dapp/token/types"
) )
...@@ -107,6 +108,19 @@ func (t *token) ExecDelLocal_TokenFinishCreate(payload *tokenty.TokenFinishCreat ...@@ -107,6 +108,19 @@ func (t *token) ExecDelLocal_TokenFinishCreate(payload *tokenty.TokenFinishCreat
var set []*types.KeyValue var set []*types.KeyValue
set = append(set, &types.KeyValue{Key: prepareKey, Value: types.Encode(localToken)}) set = append(set, &types.KeyValue{Key: prepareKey, Value: types.Encode(localToken)})
set = append(set, &types.KeyValue{Key: key, Value: nil}) set = append(set, &types.KeyValue{Key: key, Value: nil})
table := NewLogsTable(t.GetLocalDB())
txIndex := dapp.HeightIndexStr(t.GetHeight(), int64(index))
err = table.Del([]byte(txIndex))
if err != nil {
return nil, err
}
kv, err := table.Save()
if err != nil {
return nil, err
}
set = append(set, kv...)
return &types.LocalDBSet{KV: set}, nil return &types.LocalDBSet{KV: set}, nil
} }
...@@ -123,3 +137,53 @@ func (t *token) ExecDelLocal_TokenRevokeCreate(payload *tokenty.TokenRevokeCreat ...@@ -123,3 +137,53 @@ func (t *token) ExecDelLocal_TokenRevokeCreate(payload *tokenty.TokenRevokeCreat
set = append(set, &types.KeyValue{Key: prepareKey, Value: types.Encode(localToken)}) set = append(set, &types.KeyValue{Key: prepareKey, Value: types.Encode(localToken)})
return &types.LocalDBSet{KV: set}, nil return &types.LocalDBSet{KV: set}, nil
} }
func (t *token) ExecDelLocal_TokenMint(payload *tokenty.TokenMint, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
localToken, err := loadLocalToken(payload.Symbol, tx.From(), tokenty.TokenStatusCreated, t.GetLocalDB())
if err != nil {
return nil, err
}
localToken = resetMint(localToken, t.GetHeight(), t.GetBlockTime(), payload.Amount)
key := calcTokenStatusKeyLocal(payload.Symbol, tx.From(), tokenty.TokenStatusCreated)
var set []*types.KeyValue
set = append(set, &types.KeyValue{Key: key, Value: types.Encode(localToken)})
table := NewLogsTable(t.GetLocalDB())
txIndex := dapp.HeightIndexStr(t.GetHeight(), int64(index))
err = table.Del([]byte(txIndex))
if err != nil {
return nil, err
}
kv, err := table.Save()
if err != nil {
return nil, err
}
set = append(set, kv...)
return &types.LocalDBSet{KV: set}, nil
}
func (t *token) ExecDelLocal_TokenBurn(payload *tokenty.TokenBurn, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
localToken, err := loadLocalToken(payload.Symbol, tx.From(), tokenty.TokenStatusCreated, t.GetLocalDB())
if err != nil {
return nil, err
}
localToken = resetBurn(localToken, t.GetHeight(), t.GetBlockTime(), payload.Amount)
key := calcTokenStatusKeyLocal(payload.Symbol, tx.From(), tokenty.TokenStatusCreated)
var set []*types.KeyValue
set = append(set, &types.KeyValue{Key: key, Value: types.Encode(localToken)})
table := NewLogsTable(t.GetLocalDB())
txIndex := dapp.HeightIndexStr(t.GetHeight(), int64(index))
err = table.Del([]byte(txIndex))
if err != nil {
return nil, err
}
kv, err := table.Save()
if err != nil {
return nil, err
}
set = append(set, kv...)
return &types.LocalDBSet{KV: set}, nil
}
...@@ -5,7 +5,10 @@ ...@@ -5,7 +5,10 @@
package executor package executor
import ( import (
"encoding/hex"
"github.com/33cn/chain33/common/db" "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
tokenty "github.com/33cn/plugin/plugin/dapp/token/types" tokenty "github.com/33cn/plugin/plugin/dapp/token/types"
) )
...@@ -107,6 +110,19 @@ func (t *token) ExecLocal_TokenFinishCreate(payload *tokenty.TokenFinishCreate, ...@@ -107,6 +110,19 @@ func (t *token) ExecLocal_TokenFinishCreate(payload *tokenty.TokenFinishCreate,
set = append(set, &types.KeyValue{Key: key, Value: types.Encode(localToken)}) set = append(set, &types.KeyValue{Key: key, Value: types.Encode(localToken)})
kv := AddTokenToAssets(payload.Owner, t.GetLocalDB(), payload.Symbol) kv := AddTokenToAssets(payload.Owner, t.GetLocalDB(), payload.Symbol)
set = append(set, kv...) set = append(set, kv...)
table := NewLogsTable(t.GetLocalDB())
txIndex := dapp.HeightIndexStr(t.GetHeight(), int64(index))
err = table.Add(&tokenty.LocalLogs{Symbol: payload.Symbol, TxIndex: txIndex, ActionType: tokenty.TokenActionFinishCreate, TxHash: hex.EncodeToString(tx.Hash())})
if err != nil {
return nil, err
}
kv, err = table.Save()
if err != nil {
return nil, err
}
set = append(set, kv...)
return &types.LocalDBSet{KV: set}, nil return &types.LocalDBSet{KV: set}, nil
} }
...@@ -182,6 +198,16 @@ func setRevoked(t *tokenty.LocalToken, height, time int64) *tokenty.LocalToken { ...@@ -182,6 +198,16 @@ func setRevoked(t *tokenty.LocalToken, height, time int64) *tokenty.LocalToken {
return t return t
} }
func setMint(t *tokenty.LocalToken, height, time, amount int64) *tokenty.LocalToken {
t.Total = t.Total + amount
return t
}
func setBurn(t *tokenty.LocalToken, height, time, amount int64) *tokenty.LocalToken {
t.Total = t.Total - amount
return t
}
func resetCreated(t *tokenty.LocalToken) *tokenty.LocalToken { func resetCreated(t *tokenty.LocalToken) *tokenty.LocalToken {
t.CreatedTime = 0 t.CreatedTime = 0
t.CreatedHeight = 0 t.CreatedHeight = 0
...@@ -195,3 +221,63 @@ func resetRevoked(t *tokenty.LocalToken) *tokenty.LocalToken { ...@@ -195,3 +221,63 @@ func resetRevoked(t *tokenty.LocalToken) *tokenty.LocalToken {
t.Status = tokenty.TokenStatusPreCreated t.Status = tokenty.TokenStatusPreCreated
return t return t
} }
func resetMint(t *tokenty.LocalToken, height, time, amount int64) *tokenty.LocalToken {
t.Total = t.Total - amount
return t
}
func resetBurn(t *tokenty.LocalToken, height, time, amount int64) *tokenty.LocalToken {
t.Total = t.Total + amount
return t
}
func (t *token) ExecLocal_TokenMint(payload *tokenty.TokenMint, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
localToken, err := loadLocalToken(payload.Symbol, tx.From(), tokenty.TokenStatusCreated, t.GetLocalDB())
if err != nil {
return nil, err
}
localToken = setMint(localToken, t.GetHeight(), t.GetBlockTime(), payload.Amount)
var set []*types.KeyValue
key := calcTokenStatusKeyLocal(payload.Symbol, tx.From(), tokenty.TokenStatusCreated)
set = append(set, &types.KeyValue{Key: key, Value: types.Encode(localToken)})
table := NewLogsTable(t.GetLocalDB())
txIndex := dapp.HeightIndexStr(t.GetHeight(), int64(index))
err = table.Add(&tokenty.LocalLogs{Symbol: payload.Symbol, TxIndex: txIndex, ActionType: tokenty.TokenActionMint, TxHash: "0x" + hex.EncodeToString(tx.Hash())})
if err != nil {
return nil, err
}
kv, err := table.Save()
if err != nil {
return nil, err
}
set = append(set, kv...)
return &types.LocalDBSet{KV: set}, nil
}
func (t *token) ExecLocal_TokenBurn(payload *tokenty.TokenBurn, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
localToken, err := loadLocalToken(payload.Symbol, tx.From(), tokenty.TokenStatusCreated, t.GetLocalDB())
if err != nil {
return nil, err
}
localToken = setBurn(localToken, t.GetHeight(), t.GetBlockTime(), payload.Amount)
var set []*types.KeyValue
key := calcTokenStatusKeyLocal(payload.Symbol, tx.From(), tokenty.TokenStatusCreated)
set = append(set, &types.KeyValue{Key: key, Value: types.Encode(localToken)})
table := NewLogsTable(t.GetLocalDB())
txIndex := dapp.HeightIndexStr(t.GetHeight(), int64(index))
err = table.Add(&tokenty.LocalLogs{Symbol: payload.Symbol, TxIndex: txIndex, ActionType: tokenty.TokenActionBurn, TxHash: "0x" + hex.EncodeToString(tx.Hash())})
if err != nil {
return nil, err
}
kv, err := table.Save()
if err != nil {
return nil, err
}
set = append(set, kv...)
return &types.LocalDBSet{KV: set}, nil
}
// 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 executor
// 记录token 的更改记录,
// 包含创建完成, 铸币, 以后可能包含燃烧等
import (
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db/table"
"github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/token/types"
)
var opt_logs_table = &table.Option{
Prefix: "LODB-token",
Name: "logs",
Primary: "txIndex",
Index: []string{
"symbol",
},
}
// LogsRow row
type LogsRow struct {
*pty.LocalLogs
}
// NewOrderRow create row
func NewOrderRow() *LogsRow {
return &LogsRow{LocalLogs: nil}
}
// CreateRow create row
func (r *LogsRow) CreateRow() *table.Row {
return &table.Row{Data: &pty.LocalLogs{}}
}
// SetPayload set payload
func (r *LogsRow) SetPayload(data types.Message) error {
if d, ok := data.(*pty.LocalLogs); ok {
r.LocalLogs = d
return nil
}
return types.ErrTypeAsset
}
// Get get index key
func (r *LogsRow) Get(key string) ([]byte, error) {
switch key {
case "txIndex":
return []byte(r.TxIndex), nil
case "symbol":
return []byte(r.Symbol), nil
default:
return nil, types.ErrNotFound
}
}
// NewLogsTable create table
func NewLogsTable(kvdb dbm.KV) *table.Table {
rowMeta := NewOrderRow()
err := rowMeta.SetPayload(&pty.LocalLogs{})
if err != nil {
panic(err)
}
t, err := table.NewTable(rowMeta, kvdb, opt_logs_table)
if err != nil {
panic(err)
}
return t
}
func list(db dbm.KVDB, indexName string, data *pty.LocalLogs, count, direction int32) ([]*table.Row, error) {
query := NewLogsTable(db).GetQuery(db)
var primary []byte
if len(data.TxIndex) > 0 {
primary = []byte(data.TxIndex)
}
cur := &LogsRow{LocalLogs: data}
index, err := cur.Get(indexName)
if err != nil {
tokenlog.Error("query List failed", "key", string(primary), "param", data, "err", err)
return nil, err
}
tokenlog.Debug("query List dbg", "indexName", indexName, "index", string(index), "primary", primary, "count", count, "direction", direction)
rows, err := query.ListIndex(indexName, index, primary, count, direction)
if err != nil {
tokenlog.Error("query List failed", "key", string(primary), "param", data, "err", err)
return nil, err
}
if len(rows) == 0 {
return nil, types.ErrNotFound
}
return rows, nil
}
...@@ -69,3 +69,25 @@ func (t *token) Query_GetTxByToken(in *tokenty.ReqTokenTx) (types.Message, error ...@@ -69,3 +69,25 @@ func (t *token) Query_GetTxByToken(in *tokenty.ReqTokenTx) (types.Message, error
} }
return t.getTxByToken(in) return t.getTxByToken(in)
} }
// Query_GetTokenHistory 获取token 的变更历史
func (t *token) Query_GetTokenHistory(in *types.ReqString) (types.Message, error) {
if in == nil {
return nil, types.ErrInvalidParam
}
rows, err := list(t.GetLocalDB(), "symbol", &tokenty.LocalLogs{Symbol: in.Data}, -1, 0)
if err != nil {
tokenlog.Error("Query_GetTokenHistory", "err", err)
return nil, err
}
var replys tokenty.ReplyTokenLogs
for _, row := range rows {
o, ok := row.Data.(*tokenty.LocalLogs)
if !ok {
tokenlog.Error("Query_GetTokenHistory", "err", "bad row type")
return nil, types.ErrTypeAsset
}
replys.Logs = append(replys.Logs, o)
}
return &replys, nil
}
...@@ -157,6 +157,7 @@ func TestPrecreate(t *testing.T) { ...@@ -157,6 +157,7 @@ func TestPrecreate(t *testing.T) {
Total: tokenAmount, Total: tokenAmount,
Price: tokenPrice, Price: tokenPrice,
Owner: addr, Owner: addr,
Category: pty.CategoryMintBurnSupport,
} }
precreate := &pty.TokenAction{ precreate := &pty.TokenAction{
Ty: pty.TokenActionPreCreate, Ty: pty.TokenActionPreCreate,
...@@ -312,6 +313,78 @@ func TestQueryAsset(t *testing.T) { ...@@ -312,6 +313,78 @@ func TestQueryAsset(t *testing.T) {
} }
func TestTokenMint(t *testing.T) {
if !isMainNetTest {
return
}
fmt.Println("TestTokenMint start")
defer fmt.Println("TestTokenMint end")
v := &pty.TokenAction_TokenMint{TokenMint: &pty.TokenMint{Symbol: tokenSym, Amount: transAmount}}
transfer := &pty.TokenAction{Value: v, Ty: pty.ActionTransfer}
tx := &types.Transaction{Execer: []byte(execName), Payload: types.Encode(transfer), Fee: fee, To: addrexec}
tx.Nonce = r.Int63()
tx.Sign(types.SECP256K1, privkey)
reply, err := mainClient.SendTransaction(context.Background(), tx)
if err != nil {
fmt.Println("err", err)
t.Error(err)
return
}
if !reply.IsOk {
fmt.Println("err = ", reply.GetMsg())
t.Error(ErrTest)
return
}
if !waitTx(tx.Hash()) {
t.Error(ErrTest)
return
}
}
func TestQueryTokenLogs(t *testing.T) {
if !isParaNetTest {
return
}
fmt.Println("TestQueryTokenLogs start")
defer fmt.Println("TestQueryTokenLogs end")
var req types.ChainExecutor
req.Driver = execName
req.FuncName = "GetTokenHistory"
req.Param = types.Encode(&types.ReqString{Data: tokenSym})
reply, err := paraClient.QueryChain(context.Background(), &req)
if err != nil {
fmt.Println(err)
t.Error(err)
return
}
if !reply.IsOk {
fmt.Println("Query reply err")
t.Error(ErrTest)
return
}
var res pty.ReplyTokenLogs
err = types.Decode(reply.Msg, &res)
if err != nil {
t.Error(err)
return
}
assert.Equal(t, 2, len(res.Logs))
for _, l := range res.Logs {
fmt.Println(l.Symbol)
fmt.Println(l.TxHash)
fmt.Println(l.TxIndex)
fmt.Println(l.ActionType)
}
}
//*************************************************** //***************************************************
//**************common actions for Test************** //**************common actions for Test**************
//*************************************************** //***************************************************
......
package executor
import (
"testing"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/crypto"
dbm "github.com/33cn/chain33/common/db"
pty "github.com/33cn/plugin/plugin/dapp/token/types"
"github.com/stretchr/testify/assert"
//"github.com/33cn/chain33/types/jsonpb"
)
type execEnv struct {
blockTime int64
blockHeight int64
difficulty uint64
}
var (
Symbol = "TEST"
AssetExecToken = "token"
AssetExecPara = "paracross"
PrivKeyA = "0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b" // 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
PrivKeyB = "0x19c069234f9d3e61135fefbeb7791b149cdf6af536f26bebb310d4cd22c3fee4" // 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR
PrivKeyC = "0x7a80a1f75d7360c6123c32a78ecf978c1ac55636f87892df38d8b85a9aeff115" // 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k
PrivKeyD = "0xcacb1f5d51700aea07fca2246ab43b0917d70405c65edea9b5063d72eb5c6b71" // 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs
Nodes = [][]byte{
[]byte("1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"),
[]byte("1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR"),
[]byte("1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"),
[]byte("1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"),
}
)
func TestToken(t *testing.T) {
types.SetTitleOnlyForTest("chain33")
tokenTotal := int64(10000 * 1e8)
tokenBurn := int64(10 * 1e8)
tokenMint := int64(20 * 1e8)
total := int64(100000)
accountA := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[0]),
}
accountB := types.Account{
Balance: total,
Frozen: 0,
Addr: string(Nodes[1]),
}
execAddr := address.ExecAddress(pty.TokenX)
stateDB, _ := dbm.NewGoMemDB("1", "2", 100)
_, _, kvdb := util.CreateTestDB()
accA, _ := account.NewAccountDB(AssetExecPara, Symbol, stateDB)
accA.SaveExecAccount(execAddr, &accountA)
accB, _ := account.NewAccountDB(AssetExecPara, Symbol, stateDB)
accB.SaveExecAccount(execAddr, &accountB)
env := execEnv{
10,
types.GetDappFork(pty.TokenX, pty.ForkTokenSymbolWithNumberX),
1539918074,
}
// set config key
item := &types.ConfigItem{
Key: "mavl-manage-token-blacklist",
Value: &types.ConfigItem_Arr{
Arr: &types.ArrayConfig{Value: []string{"bty"}},
},
}
stateDB.Set([]byte(item.Key), types.Encode(item))
item2 := &types.ConfigItem{
Key: "mavl-manage-token-finisher",
Value: &types.ConfigItem_Arr{
Arr: &types.ArrayConfig{Value: []string{string(Nodes[0])}},
},
}
stateDB.Set([]byte(item2.Key), types.Encode(item2))
// create token
// 创建
//ty := pty.TokenType{}
p1 := &pty.TokenPreCreate{
Name: Symbol,
Symbol: Symbol,
Introduction: Symbol,
Total: tokenTotal,
Price: 0,
Owner: string(Nodes[0]),
Category: pty.CategoryMintBurnSupport,
}
//v, _ := types.PBToJSON(p1)
createTx, err := types.CallCreateTransaction(pty.TokenX, "TokenPreCreate", p1)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx, err = signTx(createTx, PrivKeyA)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec := newToken()
exec.SetStateDB(stateDB)
exec.SetLocalDB(kvdb)
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
receipt, err := exec.Exec(createTx, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
t.Log(receipt)
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptDate := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(createTx, receiptDate, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
p2 := &pty.TokenFinishCreate{
Symbol: Symbol,
Owner: string(Nodes[0]),
}
//v, _ := types.PBToJSON(p1)
createTx2, err := types.CallCreateTransaction(pty.TokenX, "TokenFinishCreate", p2)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx2, err = signTx(createTx2, PrivKeyA)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx2, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
//t.Log(receipt)
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
accDB, _ := account.NewAccountDB(pty.TokenX, Symbol, stateDB)
accChcek := accDB.LoadAccount(string(Nodes[0]))
assert.Equal(t, tokenTotal, accChcek.Balance)
receiptDate = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx2, receiptDate, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
// mint burn
p3 := &pty.TokenMint{
Symbol: Symbol,
Amount: tokenMint,
}
//v, _ := types.PBToJSON(p1)
createTx3, err := types.CallCreateTransaction(pty.TokenX, "TokenMint", p3)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx3, err = signTx(createTx3, PrivKeyA)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+2, env.blockTime+2, env.difficulty)
receipt, err = exec.Exec(createTx3, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
//t.Log(receipt)
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
accChcek = accDB.LoadAccount(string(Nodes[0]))
assert.Equal(t, tokenTotal+tokenMint, accChcek.Balance)
receiptDate = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx3, receiptDate, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
p4 := &pty.TokenBurn{
Symbol: Symbol,
Amount: tokenBurn,
}
//v, _ := types.PBToJSON(p1)
createTx4, err := types.CallCreateTransaction(pty.TokenX, "TokenBurn", p4)
if err != nil {
t.Error("RPC_Default_Process", "err", err)
}
createTx4, err = signTx(createTx4, PrivKeyA)
if err != nil {
t.Error("RPC_Default_Process sign", "err", err)
}
exec.SetEnv(env.blockHeight+1, env.blockTime+1, env.difficulty)
receipt, err = exec.Exec(createTx4, int(1))
assert.Nil(t, err)
assert.NotNil(t, receipt)
//t.Log(receipt)
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
accChcek = accDB.LoadAccount(string(Nodes[0]))
assert.Equal(t, tokenTotal+tokenMint-tokenBurn, accChcek.Balance)
receiptDate = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(createTx4, receiptDate, int(1))
assert.Nil(t, err)
assert.NotNil(t, set)
}
func signTx(tx *types.Transaction, hexPrivKey string) (*types.Transaction, error) {
signType := types.SECP256K1
c, err := crypto.New(types.GetSignName(pty.TokenX, signType))
if err != nil {
return tx, err
}
bytes, err := common.FromHex(hexPrivKey[:])
if err != nil {
return tx, err
}
privKey, err := c.PrivKeyFromBytes(bytes)
if err != nil {
return tx, err
}
tx.Sign(int32(signType), privKey)
return tx, nil
}
...@@ -40,7 +40,10 @@ func newTokenDB(preCreate *pty.TokenPreCreate, creator string, height int64) *to ...@@ -40,7 +40,10 @@ func newTokenDB(preCreate *pty.TokenPreCreate, creator string, height int64) *to
func (t *tokenDB) save(db dbm.KV, key []byte) { func (t *tokenDB) save(db dbm.KV, key []byte) {
set := t.getKVSet(key) set := t.getKVSet(key)
for i := 0; i < len(set); i++ { for i := 0; i < len(set); i++ {
db.Set(set[i].GetKey(), set[i].Value) err := db.Set(set[i].GetKey(), set[i].Value)
if err != nil {
panic(err)
}
} }
} }
...@@ -59,6 +62,48 @@ func (t *tokenDB) getKVSet(key []byte) (kvset []*types.KeyValue) { ...@@ -59,6 +62,48 @@ func (t *tokenDB) getKVSet(key []byte) (kvset []*types.KeyValue) {
return kvset return kvset
} }
func loadTokenDB(db dbm.KV, symbol string) (*tokenDB, error) {
token, err := db.Get(calcTokenKey(symbol))
if err != nil {
tokenlog.Error("tokendb load ", "Can't get token form db for token", symbol)
return nil, pty.ErrTokenNotExist
}
var t pty.Token
err = types.Decode(token, &t)
if err != nil {
tokenlog.Error("tokendb load", "Can't decode token info", symbol)
return nil, err
}
return &tokenDB{t}, nil
}
func (t *tokenDB) mint(db dbm.KV, addr string, amount int64) ([]*types.KeyValue, []*types.ReceiptLog, error) {
if t.token.Owner != addr {
return nil, nil, types.ErrNotAllow
}
if t.token.Total+amount > types.MaxTokenBalance {
return nil, nil, types.ErrAmount
}
prevToken := t.token
t.token.Total += amount
kvs := append(t.getKVSet(calcTokenKey(t.token.Symbol)), t.getKVSet(calcTokenAddrNewKeyS(t.token.Symbol, t.token.Owner))...)
logs := []*types.ReceiptLog{{Ty: pty.TyLogTokenMint, Log: types.Encode(&pty.ReceiptTokenAmount{Prev: &prevToken, Current: &t.token})}}
return kvs, logs, nil
}
func (t *tokenDB) burn(db dbm.KV, amount int64) ([]*types.KeyValue, []*types.ReceiptLog, error) {
if t.token.Total < amount {
return nil, nil, types.ErrNoBalance
}
prevToken := t.token
t.token.Total -= amount
kvs := append(t.getKVSet(calcTokenKey(t.token.Symbol)), t.getKVSet(calcTokenAddrNewKeyS(t.token.Symbol, t.token.Owner))...)
logs := []*types.ReceiptLog{{Ty: pty.TyLogTokenBurn, Log: types.Encode(&pty.ReceiptTokenAmount{Prev: &prevToken, Current: &t.token})}}
return kvs, logs, nil
}
func getTokenFromDB(db dbm.KV, symbol string, owner string) (*pty.Token, error) { func getTokenFromDB(db dbm.KV, symbol string, owner string) (*pty.Token, error) {
key := calcTokenAddrKeyS(symbol, owner) key := calcTokenAddrKeyS(symbol, owner)
value, err := db.Get(key) value, err := db.Get(key)
...@@ -468,3 +513,87 @@ func validSymbolWithHeight(cs []byte, height int64) bool { ...@@ -468,3 +513,87 @@ func validSymbolWithHeight(cs []byte, height int64) bool {
} }
return validSymbolOriginal(cs) return validSymbolOriginal(cs)
} }
// 铸币不可控, 也是麻烦。 2选1
// 1. 谁可以发起
// 2. 是否需要审核 这个会增加管理的成本
// 现在实现选择 1
func (action *tokenAction) mint(mint *pty.TokenMint) (*types.Receipt, error) {
if mint == nil {
return nil, types.ErrInvalidParam
}
if mint.GetAmount() < 0 || mint.GetAmount() > types.MaxTokenBalance || mint.GetSymbol() == "" {
return nil, types.ErrInvalidParam
}
tokendb, err := loadTokenDB(action.db, mint.GetSymbol())
if err != nil {
return nil, err
}
if tokendb.token.Category&pty.CategoryMintBurnSupport == 0 {
tokenlog.Error("Can't mint category", "category", tokendb.token.Category, "support", pty.CategoryMintBurnSupport)
return nil, types.ErrNotSupport
}
kvs, logs, err := tokendb.mint(action.db, action.fromaddr, mint.Amount)
if err != nil {
tokenlog.Error("token mint ", "symbol", mint.GetSymbol(), "error", err, "from", action.fromaddr, "owner", tokendb.token.Owner)
return nil, err
}
tokenAccount, err := account.NewAccountDB("token", mint.GetSymbol(), action.db)
if err != nil {
return nil, err
}
tokenlog.Debug("mint", "token.Owner", mint.Symbol, "token.GetTotal()", mint.Amount)
receipt, err := tokenAccount.Mint(action.fromaddr, mint.Amount)
if err != nil {
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
return &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}, nil
}
func (action *tokenAction) burn(burn *pty.TokenBurn) (*types.Receipt, error) {
if burn == nil {
return nil, types.ErrInvalidParam
}
if burn.GetAmount() < 0 || burn.GetAmount() > types.MaxTokenBalance || burn.GetSymbol() == "" {
return nil, types.ErrInvalidParam
}
tokendb, err := loadTokenDB(action.db, burn.GetSymbol())
if err != nil {
return nil, err
}
if tokendb.token.Category&pty.CategoryMintBurnSupport == 0 {
tokenlog.Error("Can't burn category", "category", tokendb.token.Category, "support", pty.CategoryMintBurnSupport)
return nil, types.ErrNotSupport
}
kvs, logs, err := tokendb.burn(action.db, burn.Amount)
if err != nil {
tokenlog.Error("token burn ", "symbol", burn.GetSymbol(), "error", err, "from", action.fromaddr, "owner", tokendb.token.Owner)
return nil, err
}
tokenAccount, err := account.NewAccountDB("token", burn.GetSymbol(), action.db)
if err != nil {
return nil, err
}
tokenlog.Debug("burn", "token.Owner", burn.Symbol, "token.GetTotal()", burn.Amount)
receipt, err := tokenAccount.Burn(action.fromaddr, burn.Amount)
if err != nil {
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
return &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}, nil
}
...@@ -172,7 +172,10 @@ func updateAddrReciver(cachedb dbm.KVDB, token string, addr string, amount int64 ...@@ -172,7 +172,10 @@ func updateAddrReciver(cachedb dbm.KVDB, token string, addr string, amount int64
} else { } else {
recv -= amount recv -= amount
} }
setAddrReciver(cachedb, token, addr, recv) err = setAddrReciver(cachedb, token, addr, recv)
if err != nil {
return nil, err
}
//keyvalue //keyvalue
return getAddrReciverKV(token, addr, recv), nil return getAddrReciverKV(token, addr, recv), nil
} }
...@@ -15,6 +15,8 @@ message TokenAction { ...@@ -15,6 +15,8 @@ message TokenAction {
AssetsWithdraw withdraw = 5; AssetsWithdraw withdraw = 5;
AssetsGenesis genesis = 6; AssetsGenesis genesis = 6;
AssetsTransferToExec transferToExec = 8; AssetsTransferToExec transferToExec = 8;
TokenMint tokenMint = 9;
TokenBurn tokenBurn = 10;
} }
int32 Ty = 7; int32 Ty = 7;
} }
...@@ -40,6 +42,16 @@ message TokenRevokeCreate { ...@@ -40,6 +42,16 @@ message TokenRevokeCreate {
string owner = 2; string owner = 2;
} }
message TokenMint {
string symbol = 1;
int64 amount = 2;
}
message TokenBurn {
string symbol = 1;
int64 amount = 2;
}
// state db // state db
message Token { message Token {
string name = 1; string name = 1;
...@@ -60,6 +72,11 @@ message ReceiptToken { ...@@ -60,6 +72,11 @@ message ReceiptToken {
int32 status = 3; int32 status = 3;
} }
message ReceiptTokenAmount {
Token prev = 1;
Token current = 2;
}
// local // local
message LocalToken { message LocalToken {
string name = 1; string name = 1;
...@@ -82,6 +99,13 @@ message LocalToken { ...@@ -82,6 +99,13 @@ message LocalToken {
int32 category = 17; int32 category = 17;
} }
message LocalLogs {
string symbol = 1;
string txIndex = 2;
int32 actionType = 3;
string txHash = 4;
}
// query // query
message ReqTokens { message ReqTokens {
bool queryAll = 1; bool queryAll = 1;
...@@ -142,6 +166,10 @@ message ReqTokenTx { ...@@ -142,6 +166,10 @@ message ReqTokenTx {
string addr = 7; string addr = 7;
} }
message ReplyTokenLogs {
repeated LocalLogs logs = 1;
}
service token { service token {
// token 对外提供服务的接口 // token 对外提供服务的接口
//区块链接口 //区块链接口
......
...@@ -121,3 +121,29 @@ func (c *Jrpc) CreateRawTokenRevokeTx(param *tokenty.TokenRevokeCreate, result * ...@@ -121,3 +121,29 @@ func (c *Jrpc) CreateRawTokenRevokeTx(param *tokenty.TokenRevokeCreate, result *
*result = hex.EncodeToString(data) *result = hex.EncodeToString(data)
return nil return nil
} }
// CreateRawTokenMintTx 创建未签名的mint Token交易
func (c *Jrpc) CreateRawTokenMintTx(param *tokenty.TokenMint, result *interface{}) error {
if param == nil || param.Symbol == "" || param.Amount <= 0 {
return types.ErrInvalidParam
}
data, err := types.CallCreateTx(types.ExecName(tokenty.TokenX), "TokenMint", param)
if err != nil {
return err
}
*result = hex.EncodeToString(data)
return nil
}
// CreateRawTokenBurnTx 创建未签名的 burn Token交易
func (c *Jrpc) CreateRawTokenBurnTx(param *tokenty.TokenBurn, result *interface{}) error {
if param == nil || param.Symbol == "" || param.Amount <= 0 {
return types.ErrInvalidParam
}
data, err := types.CallCreateTx(types.ExecName(tokenty.TokenX), "TokenBurn", param)
if err != nil {
return err
}
*result = hex.EncodeToString(data)
return nil
}
...@@ -19,6 +19,10 @@ const ( ...@@ -19,6 +19,10 @@ const (
TokenActionRevokeCreate = 9 TokenActionRevokeCreate = 9
// TokenActionTransferToExec for token transfer to exec // TokenActionTransferToExec for token transfer to exec
TokenActionTransferToExec = 11 TokenActionTransferToExec = 11
// TokenActionMint for token mint
TokenActionMint = 12
// TokenActionBurn for token burn
TokenActionBurn = 13
) )
// token status // token status
...@@ -72,6 +76,10 @@ const ( ...@@ -72,6 +76,10 @@ const (
TyLogTokenGenesisTransfer = 321 TyLogTokenGenesisTransfer = 321
// TyLogTokenGenesisDeposit log for token genesis deposit // TyLogTokenGenesisDeposit log for token genesis deposit
TyLogTokenGenesisDeposit = 322 TyLogTokenGenesisDeposit = 322
// TyLogTokenMint log for token mint
TyLogTokenMint = 323
// TyLogTokenBurn log for token burn
TyLogTokenBurn = 324
) )
const ( const (
...@@ -82,3 +90,8 @@ const ( ...@@ -82,3 +90,8 @@ const (
// TokenIntroLenLimit token introduction length limit // TokenIntroLenLimit token introduction length limit
TokenIntroLenLimit = 1024 TokenIntroLenLimit = 1024
) )
const (
// CategoryMintBurnSupport support mint & burn
CategoryMintBurnSupport = 1 << iota
)
...@@ -34,6 +34,8 @@ type TokenAction struct { ...@@ -34,6 +34,8 @@ type TokenAction struct {
// *TokenAction_Withdraw // *TokenAction_Withdraw
// *TokenAction_Genesis // *TokenAction_Genesis
// *TokenAction_TransferToExec // *TokenAction_TransferToExec
// *TokenAction_TokenMint
// *TokenAction_TokenBurn
Value isTokenAction_Value `protobuf_oneof:"value"` Value isTokenAction_Value `protobuf_oneof:"value"`
Ty int32 `protobuf:"varint,7,opt,name=Ty,proto3" json:"Ty,omitempty"` Ty int32 `protobuf:"varint,7,opt,name=Ty,proto3" json:"Ty,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
...@@ -98,6 +100,14 @@ type TokenAction_TransferToExec struct { ...@@ -98,6 +100,14 @@ type TokenAction_TransferToExec struct {
TransferToExec *types.AssetsTransferToExec `protobuf:"bytes,8,opt,name=transferToExec,proto3,oneof"` TransferToExec *types.AssetsTransferToExec `protobuf:"bytes,8,opt,name=transferToExec,proto3,oneof"`
} }
type TokenAction_TokenMint struct {
TokenMint *TokenMint `protobuf:"bytes,9,opt,name=tokenMint,proto3,oneof"`
}
type TokenAction_TokenBurn struct {
TokenBurn *TokenBurn `protobuf:"bytes,10,opt,name=tokenBurn,proto3,oneof"`
}
func (*TokenAction_TokenPreCreate) isTokenAction_Value() {} func (*TokenAction_TokenPreCreate) isTokenAction_Value() {}
func (*TokenAction_TokenFinishCreate) isTokenAction_Value() {} func (*TokenAction_TokenFinishCreate) isTokenAction_Value() {}
...@@ -112,6 +122,10 @@ func (*TokenAction_Genesis) isTokenAction_Value() {} ...@@ -112,6 +122,10 @@ func (*TokenAction_Genesis) isTokenAction_Value() {}
func (*TokenAction_TransferToExec) isTokenAction_Value() {} func (*TokenAction_TransferToExec) isTokenAction_Value() {}
func (*TokenAction_TokenMint) isTokenAction_Value() {}
func (*TokenAction_TokenBurn) isTokenAction_Value() {}
func (m *TokenAction) GetValue() isTokenAction_Value { func (m *TokenAction) GetValue() isTokenAction_Value {
if m != nil { if m != nil {
return m.Value return m.Value
...@@ -168,6 +182,20 @@ func (m *TokenAction) GetTransferToExec() *types.AssetsTransferToExec { ...@@ -168,6 +182,20 @@ func (m *TokenAction) GetTransferToExec() *types.AssetsTransferToExec {
return nil return nil
} }
func (m *TokenAction) GetTokenMint() *TokenMint {
if x, ok := m.GetValue().(*TokenAction_TokenMint); ok {
return x.TokenMint
}
return nil
}
func (m *TokenAction) GetTokenBurn() *TokenBurn {
if x, ok := m.GetValue().(*TokenAction_TokenBurn); ok {
return x.TokenBurn
}
return nil
}
func (m *TokenAction) GetTy() int32 { func (m *TokenAction) GetTy() int32 {
if m != nil { if m != nil {
return m.Ty return m.Ty
...@@ -185,6 +213,8 @@ func (*TokenAction) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) e ...@@ -185,6 +213,8 @@ func (*TokenAction) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) e
(*TokenAction_Withdraw)(nil), (*TokenAction_Withdraw)(nil),
(*TokenAction_Genesis)(nil), (*TokenAction_Genesis)(nil),
(*TokenAction_TransferToExec)(nil), (*TokenAction_TransferToExec)(nil),
(*TokenAction_TokenMint)(nil),
(*TokenAction_TokenBurn)(nil),
} }
} }
...@@ -227,6 +257,16 @@ func _TokenAction_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { ...@@ -227,6 +257,16 @@ func _TokenAction_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
if err := b.EncodeMessage(x.TransferToExec); err != nil { if err := b.EncodeMessage(x.TransferToExec); err != nil {
return err return err
} }
case *TokenAction_TokenMint:
b.EncodeVarint(9<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.TokenMint); err != nil {
return err
}
case *TokenAction_TokenBurn:
b.EncodeVarint(10<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.TokenBurn); err != nil {
return err
}
case nil: case nil:
default: default:
return fmt.Errorf("TokenAction.Value has unexpected type %T", x) return fmt.Errorf("TokenAction.Value has unexpected type %T", x)
...@@ -293,6 +333,22 @@ func _TokenAction_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Bu ...@@ -293,6 +333,22 @@ func _TokenAction_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Bu
err := b.DecodeMessage(msg) err := b.DecodeMessage(msg)
m.Value = &TokenAction_TransferToExec{msg} m.Value = &TokenAction_TransferToExec{msg}
return true, err return true, err
case 9: // value.tokenMint
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(TokenMint)
err := b.DecodeMessage(msg)
m.Value = &TokenAction_TokenMint{msg}
return true, err
case 10: // value.tokenBurn
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(TokenBurn)
err := b.DecodeMessage(msg)
m.Value = &TokenAction_TokenBurn{msg}
return true, err
default: default:
return false, nil return false, nil
} }
...@@ -337,6 +393,16 @@ func _TokenAction_OneofSizer(msg proto.Message) (n int) { ...@@ -337,6 +393,16 @@ func _TokenAction_OneofSizer(msg proto.Message) (n int) {
n += 1 // tag and wire n += 1 // tag and wire
n += proto.SizeVarint(uint64(s)) n += proto.SizeVarint(uint64(s))
n += s n += s
case *TokenAction_TokenMint:
s := proto.Size(x.TokenMint)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case *TokenAction_TokenBurn:
s := proto.Size(x.TokenBurn)
n += 1 // tag and wire
n += proto.SizeVarint(uint64(s))
n += s
case nil: case nil:
default: default:
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
...@@ -526,6 +592,100 @@ func (m *TokenRevokeCreate) GetOwner() string { ...@@ -526,6 +592,100 @@ func (m *TokenRevokeCreate) GetOwner() string {
return "" return ""
} }
type TokenMint struct {
Symbol string `protobuf:"bytes,1,opt,name=symbol,proto3" json:"symbol,omitempty"`
Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *TokenMint) Reset() { *m = TokenMint{} }
func (m *TokenMint) String() string { return proto.CompactTextString(m) }
func (*TokenMint) ProtoMessage() {}
func (*TokenMint) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{4}
}
func (m *TokenMint) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_TokenMint.Unmarshal(m, b)
}
func (m *TokenMint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_TokenMint.Marshal(b, m, deterministic)
}
func (m *TokenMint) XXX_Merge(src proto.Message) {
xxx_messageInfo_TokenMint.Merge(m, src)
}
func (m *TokenMint) XXX_Size() int {
return xxx_messageInfo_TokenMint.Size(m)
}
func (m *TokenMint) XXX_DiscardUnknown() {
xxx_messageInfo_TokenMint.DiscardUnknown(m)
}
var xxx_messageInfo_TokenMint proto.InternalMessageInfo
func (m *TokenMint) GetSymbol() string {
if m != nil {
return m.Symbol
}
return ""
}
func (m *TokenMint) GetAmount() int64 {
if m != nil {
return m.Amount
}
return 0
}
type TokenBurn struct {
Symbol string `protobuf:"bytes,1,opt,name=symbol,proto3" json:"symbol,omitempty"`
Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *TokenBurn) Reset() { *m = TokenBurn{} }
func (m *TokenBurn) String() string { return proto.CompactTextString(m) }
func (*TokenBurn) ProtoMessage() {}
func (*TokenBurn) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{5}
}
func (m *TokenBurn) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_TokenBurn.Unmarshal(m, b)
}
func (m *TokenBurn) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_TokenBurn.Marshal(b, m, deterministic)
}
func (m *TokenBurn) XXX_Merge(src proto.Message) {
xxx_messageInfo_TokenBurn.Merge(m, src)
}
func (m *TokenBurn) XXX_Size() int {
return xxx_messageInfo_TokenBurn.Size(m)
}
func (m *TokenBurn) XXX_DiscardUnknown() {
xxx_messageInfo_TokenBurn.DiscardUnknown(m)
}
var xxx_messageInfo_TokenBurn proto.InternalMessageInfo
func (m *TokenBurn) GetSymbol() string {
if m != nil {
return m.Symbol
}
return ""
}
func (m *TokenBurn) GetAmount() int64 {
if m != nil {
return m.Amount
}
return 0
}
// state db // state db
type Token struct { type Token struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
...@@ -546,7 +706,7 @@ func (m *Token) Reset() { *m = Token{} } ...@@ -546,7 +706,7 @@ func (m *Token) Reset() { *m = Token{} }
func (m *Token) String() string { return proto.CompactTextString(m) } func (m *Token) String() string { return proto.CompactTextString(m) }
func (*Token) ProtoMessage() {} func (*Token) ProtoMessage() {}
func (*Token) Descriptor() ([]byte, []int) { func (*Token) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{4} return fileDescriptor_3aff0bcd502840ab, []int{6}
} }
func (m *Token) XXX_Unmarshal(b []byte) error { func (m *Token) XXX_Unmarshal(b []byte) error {
...@@ -644,7 +804,7 @@ func (m *ReceiptToken) Reset() { *m = ReceiptToken{} } ...@@ -644,7 +804,7 @@ func (m *ReceiptToken) Reset() { *m = ReceiptToken{} }
func (m *ReceiptToken) String() string { return proto.CompactTextString(m) } func (m *ReceiptToken) String() string { return proto.CompactTextString(m) }
func (*ReceiptToken) ProtoMessage() {} func (*ReceiptToken) ProtoMessage() {}
func (*ReceiptToken) Descriptor() ([]byte, []int) { func (*ReceiptToken) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{5} return fileDescriptor_3aff0bcd502840ab, []int{7}
} }
func (m *ReceiptToken) XXX_Unmarshal(b []byte) error { func (m *ReceiptToken) XXX_Unmarshal(b []byte) error {
...@@ -686,6 +846,53 @@ func (m *ReceiptToken) GetStatus() int32 { ...@@ -686,6 +846,53 @@ func (m *ReceiptToken) GetStatus() int32 {
return 0 return 0
} }
type ReceiptTokenAmount struct {
Prev *Token `protobuf:"bytes,1,opt,name=prev,proto3" json:"prev,omitempty"`
Current *Token `protobuf:"bytes,2,opt,name=current,proto3" json:"current,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReceiptTokenAmount) Reset() { *m = ReceiptTokenAmount{} }
func (m *ReceiptTokenAmount) String() string { return proto.CompactTextString(m) }
func (*ReceiptTokenAmount) ProtoMessage() {}
func (*ReceiptTokenAmount) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{8}
}
func (m *ReceiptTokenAmount) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptTokenAmount.Unmarshal(m, b)
}
func (m *ReceiptTokenAmount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReceiptTokenAmount.Marshal(b, m, deterministic)
}
func (m *ReceiptTokenAmount) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReceiptTokenAmount.Merge(m, src)
}
func (m *ReceiptTokenAmount) XXX_Size() int {
return xxx_messageInfo_ReceiptTokenAmount.Size(m)
}
func (m *ReceiptTokenAmount) XXX_DiscardUnknown() {
xxx_messageInfo_ReceiptTokenAmount.DiscardUnknown(m)
}
var xxx_messageInfo_ReceiptTokenAmount proto.InternalMessageInfo
func (m *ReceiptTokenAmount) GetPrev() *Token {
if m != nil {
return m.Prev
}
return nil
}
func (m *ReceiptTokenAmount) GetCurrent() *Token {
if m != nil {
return m.Current
}
return nil
}
// local // local
type LocalToken struct { type LocalToken struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
...@@ -715,7 +922,7 @@ func (m *LocalToken) Reset() { *m = LocalToken{} } ...@@ -715,7 +922,7 @@ func (m *LocalToken) Reset() { *m = LocalToken{} }
func (m *LocalToken) String() string { return proto.CompactTextString(m) } func (m *LocalToken) String() string { return proto.CompactTextString(m) }
func (*LocalToken) ProtoMessage() {} func (*LocalToken) ProtoMessage() {}
func (*LocalToken) Descriptor() ([]byte, []int) { func (*LocalToken) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{6} return fileDescriptor_3aff0bcd502840ab, []int{9}
} }
func (m *LocalToken) XXX_Unmarshal(b []byte) error { func (m *LocalToken) XXX_Unmarshal(b []byte) error {
...@@ -855,6 +1062,69 @@ func (m *LocalToken) GetCategory() int32 { ...@@ -855,6 +1062,69 @@ func (m *LocalToken) GetCategory() int32 {
return 0 return 0
} }
type LocalLogs struct {
Symbol string `protobuf:"bytes,1,opt,name=symbol,proto3" json:"symbol,omitempty"`
TxIndex string `protobuf:"bytes,2,opt,name=txIndex,proto3" json:"txIndex,omitempty"`
ActionType int32 `protobuf:"varint,3,opt,name=actionType,proto3" json:"actionType,omitempty"`
TxHash string `protobuf:"bytes,4,opt,name=txHash,proto3" json:"txHash,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *LocalLogs) Reset() { *m = LocalLogs{} }
func (m *LocalLogs) String() string { return proto.CompactTextString(m) }
func (*LocalLogs) ProtoMessage() {}
func (*LocalLogs) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{10}
}
func (m *LocalLogs) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_LocalLogs.Unmarshal(m, b)
}
func (m *LocalLogs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_LocalLogs.Marshal(b, m, deterministic)
}
func (m *LocalLogs) XXX_Merge(src proto.Message) {
xxx_messageInfo_LocalLogs.Merge(m, src)
}
func (m *LocalLogs) XXX_Size() int {
return xxx_messageInfo_LocalLogs.Size(m)
}
func (m *LocalLogs) XXX_DiscardUnknown() {
xxx_messageInfo_LocalLogs.DiscardUnknown(m)
}
var xxx_messageInfo_LocalLogs proto.InternalMessageInfo
func (m *LocalLogs) GetSymbol() string {
if m != nil {
return m.Symbol
}
return ""
}
func (m *LocalLogs) GetTxIndex() string {
if m != nil {
return m.TxIndex
}
return ""
}
func (m *LocalLogs) GetActionType() int32 {
if m != nil {
return m.ActionType
}
return 0
}
func (m *LocalLogs) GetTxHash() string {
if m != nil {
return m.TxHash
}
return ""
}
// query // query
type ReqTokens struct { type ReqTokens struct {
QueryAll bool `protobuf:"varint,1,opt,name=queryAll,proto3" json:"queryAll,omitempty"` QueryAll bool `protobuf:"varint,1,opt,name=queryAll,proto3" json:"queryAll,omitempty"`
...@@ -870,7 +1140,7 @@ func (m *ReqTokens) Reset() { *m = ReqTokens{} } ...@@ -870,7 +1140,7 @@ func (m *ReqTokens) Reset() { *m = ReqTokens{} }
func (m *ReqTokens) String() string { return proto.CompactTextString(m) } func (m *ReqTokens) String() string { return proto.CompactTextString(m) }
func (*ReqTokens) ProtoMessage() {} func (*ReqTokens) ProtoMessage() {}
func (*ReqTokens) Descriptor() ([]byte, []int) { func (*ReqTokens) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{7} return fileDescriptor_3aff0bcd502840ab, []int{11}
} }
func (m *ReqTokens) XXX_Unmarshal(b []byte) error { func (m *ReqTokens) XXX_Unmarshal(b []byte) error {
...@@ -930,7 +1200,7 @@ func (m *ReplyTokens) Reset() { *m = ReplyTokens{} } ...@@ -930,7 +1200,7 @@ func (m *ReplyTokens) Reset() { *m = ReplyTokens{} }
func (m *ReplyTokens) String() string { return proto.CompactTextString(m) } func (m *ReplyTokens) String() string { return proto.CompactTextString(m) }
func (*ReplyTokens) ProtoMessage() {} func (*ReplyTokens) ProtoMessage() {}
func (*ReplyTokens) Descriptor() ([]byte, []int) { func (*ReplyTokens) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{8} return fileDescriptor_3aff0bcd502840ab, []int{12}
} }
func (m *ReplyTokens) XXX_Unmarshal(b []byte) error { func (m *ReplyTokens) XXX_Unmarshal(b []byte) error {
...@@ -970,7 +1240,7 @@ func (m *TokenRecv) Reset() { *m = TokenRecv{} } ...@@ -970,7 +1240,7 @@ func (m *TokenRecv) Reset() { *m = TokenRecv{} }
func (m *TokenRecv) String() string { return proto.CompactTextString(m) } func (m *TokenRecv) String() string { return proto.CompactTextString(m) }
func (*TokenRecv) ProtoMessage() {} func (*TokenRecv) ProtoMessage() {}
func (*TokenRecv) Descriptor() ([]byte, []int) { func (*TokenRecv) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{9} return fileDescriptor_3aff0bcd502840ab, []int{13}
} }
func (m *TokenRecv) XXX_Unmarshal(b []byte) error { func (m *TokenRecv) XXX_Unmarshal(b []byte) error {
...@@ -1016,7 +1286,7 @@ func (m *ReplyAddrRecvForTokens) Reset() { *m = ReplyAddrRecvForTokens{} ...@@ -1016,7 +1286,7 @@ func (m *ReplyAddrRecvForTokens) Reset() { *m = ReplyAddrRecvForTokens{}
func (m *ReplyAddrRecvForTokens) String() string { return proto.CompactTextString(m) } func (m *ReplyAddrRecvForTokens) String() string { return proto.CompactTextString(m) }
func (*ReplyAddrRecvForTokens) ProtoMessage() {} func (*ReplyAddrRecvForTokens) ProtoMessage() {}
func (*ReplyAddrRecvForTokens) Descriptor() ([]byte, []int) { func (*ReplyAddrRecvForTokens) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{10} return fileDescriptor_3aff0bcd502840ab, []int{14}
} }
func (m *ReplyAddrRecvForTokens) XXX_Unmarshal(b []byte) error { func (m *ReplyAddrRecvForTokens) XXX_Unmarshal(b []byte) error {
...@@ -1057,7 +1327,7 @@ func (m *ReqTokenBalance) Reset() { *m = ReqTokenBalance{} } ...@@ -1057,7 +1327,7 @@ func (m *ReqTokenBalance) Reset() { *m = ReqTokenBalance{} }
func (m *ReqTokenBalance) String() string { return proto.CompactTextString(m) } func (m *ReqTokenBalance) String() string { return proto.CompactTextString(m) }
func (*ReqTokenBalance) ProtoMessage() {} func (*ReqTokenBalance) ProtoMessage() {}
func (*ReqTokenBalance) Descriptor() ([]byte, []int) { func (*ReqTokenBalance) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{11} return fileDescriptor_3aff0bcd502840ab, []int{15}
} }
func (m *ReqTokenBalance) XXX_Unmarshal(b []byte) error { func (m *ReqTokenBalance) XXX_Unmarshal(b []byte) error {
...@@ -1111,7 +1381,7 @@ func (m *ReqAccountTokenAssets) Reset() { *m = ReqAccountTokenAssets{} } ...@@ -1111,7 +1381,7 @@ func (m *ReqAccountTokenAssets) Reset() { *m = ReqAccountTokenAssets{} }
func (m *ReqAccountTokenAssets) String() string { return proto.CompactTextString(m) } func (m *ReqAccountTokenAssets) String() string { return proto.CompactTextString(m) }
func (*ReqAccountTokenAssets) ProtoMessage() {} func (*ReqAccountTokenAssets) ProtoMessage() {}
func (*ReqAccountTokenAssets) Descriptor() ([]byte, []int) { func (*ReqAccountTokenAssets) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{12} return fileDescriptor_3aff0bcd502840ab, []int{16}
} }
func (m *ReqAccountTokenAssets) XXX_Unmarshal(b []byte) error { func (m *ReqAccountTokenAssets) XXX_Unmarshal(b []byte) error {
...@@ -1158,7 +1428,7 @@ func (m *TokenAsset) Reset() { *m = TokenAsset{} } ...@@ -1158,7 +1428,7 @@ func (m *TokenAsset) Reset() { *m = TokenAsset{} }
func (m *TokenAsset) String() string { return proto.CompactTextString(m) } func (m *TokenAsset) String() string { return proto.CompactTextString(m) }
func (*TokenAsset) ProtoMessage() {} func (*TokenAsset) ProtoMessage() {}
func (*TokenAsset) Descriptor() ([]byte, []int) { func (*TokenAsset) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{13} return fileDescriptor_3aff0bcd502840ab, []int{17}
} }
func (m *TokenAsset) XXX_Unmarshal(b []byte) error { func (m *TokenAsset) XXX_Unmarshal(b []byte) error {
...@@ -1204,7 +1474,7 @@ func (m *ReplyAccountTokenAssets) Reset() { *m = ReplyAccountTokenAssets ...@@ -1204,7 +1474,7 @@ func (m *ReplyAccountTokenAssets) Reset() { *m = ReplyAccountTokenAssets
func (m *ReplyAccountTokenAssets) String() string { return proto.CompactTextString(m) } func (m *ReplyAccountTokenAssets) String() string { return proto.CompactTextString(m) }
func (*ReplyAccountTokenAssets) ProtoMessage() {} func (*ReplyAccountTokenAssets) ProtoMessage() {}
func (*ReplyAccountTokenAssets) Descriptor() ([]byte, []int) { func (*ReplyAccountTokenAssets) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{14} return fileDescriptor_3aff0bcd502840ab, []int{18}
} }
func (m *ReplyAccountTokenAssets) XXX_Unmarshal(b []byte) error { func (m *ReplyAccountTokenAssets) XXX_Unmarshal(b []byte) error {
...@@ -1248,7 +1518,7 @@ func (m *ReqAddrTokens) Reset() { *m = ReqAddrTokens{} } ...@@ -1248,7 +1518,7 @@ func (m *ReqAddrTokens) Reset() { *m = ReqAddrTokens{} }
func (m *ReqAddrTokens) String() string { return proto.CompactTextString(m) } func (m *ReqAddrTokens) String() string { return proto.CompactTextString(m) }
func (*ReqAddrTokens) ProtoMessage() {} func (*ReqAddrTokens) ProtoMessage() {}
func (*ReqAddrTokens) Descriptor() ([]byte, []int) { func (*ReqAddrTokens) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{15} return fileDescriptor_3aff0bcd502840ab, []int{19}
} }
func (m *ReqAddrTokens) XXX_Unmarshal(b []byte) error { func (m *ReqAddrTokens) XXX_Unmarshal(b []byte) error {
...@@ -1329,7 +1599,7 @@ func (m *ReqTokenTx) Reset() { *m = ReqTokenTx{} } ...@@ -1329,7 +1599,7 @@ func (m *ReqTokenTx) Reset() { *m = ReqTokenTx{} }
func (m *ReqTokenTx) String() string { return proto.CompactTextString(m) } func (m *ReqTokenTx) String() string { return proto.CompactTextString(m) }
func (*ReqTokenTx) ProtoMessage() {} func (*ReqTokenTx) ProtoMessage() {}
func (*ReqTokenTx) Descriptor() ([]byte, []int) { func (*ReqTokenTx) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{16} return fileDescriptor_3aff0bcd502840ab, []int{20}
} }
func (m *ReqTokenTx) XXX_Unmarshal(b []byte) error { func (m *ReqTokenTx) XXX_Unmarshal(b []byte) error {
...@@ -1399,14 +1669,57 @@ func (m *ReqTokenTx) GetAddr() string { ...@@ -1399,14 +1669,57 @@ func (m *ReqTokenTx) GetAddr() string {
return "" return ""
} }
type ReplyTokenLogs struct {
Logs []*LocalLogs `protobuf:"bytes,1,rep,name=logs,proto3" json:"logs,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReplyTokenLogs) Reset() { *m = ReplyTokenLogs{} }
func (m *ReplyTokenLogs) String() string { return proto.CompactTextString(m) }
func (*ReplyTokenLogs) ProtoMessage() {}
func (*ReplyTokenLogs) Descriptor() ([]byte, []int) {
return fileDescriptor_3aff0bcd502840ab, []int{21}
}
func (m *ReplyTokenLogs) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReplyTokenLogs.Unmarshal(m, b)
}
func (m *ReplyTokenLogs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReplyTokenLogs.Marshal(b, m, deterministic)
}
func (m *ReplyTokenLogs) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReplyTokenLogs.Merge(m, src)
}
func (m *ReplyTokenLogs) XXX_Size() int {
return xxx_messageInfo_ReplyTokenLogs.Size(m)
}
func (m *ReplyTokenLogs) XXX_DiscardUnknown() {
xxx_messageInfo_ReplyTokenLogs.DiscardUnknown(m)
}
var xxx_messageInfo_ReplyTokenLogs proto.InternalMessageInfo
func (m *ReplyTokenLogs) GetLogs() []*LocalLogs {
if m != nil {
return m.Logs
}
return nil
}
func init() { func init() {
proto.RegisterType((*TokenAction)(nil), "types.TokenAction") proto.RegisterType((*TokenAction)(nil), "types.TokenAction")
proto.RegisterType((*TokenPreCreate)(nil), "types.TokenPreCreate") proto.RegisterType((*TokenPreCreate)(nil), "types.TokenPreCreate")
proto.RegisterType((*TokenFinishCreate)(nil), "types.TokenFinishCreate") proto.RegisterType((*TokenFinishCreate)(nil), "types.TokenFinishCreate")
proto.RegisterType((*TokenRevokeCreate)(nil), "types.TokenRevokeCreate") proto.RegisterType((*TokenRevokeCreate)(nil), "types.TokenRevokeCreate")
proto.RegisterType((*TokenMint)(nil), "types.TokenMint")
proto.RegisterType((*TokenBurn)(nil), "types.TokenBurn")
proto.RegisterType((*Token)(nil), "types.Token") proto.RegisterType((*Token)(nil), "types.Token")
proto.RegisterType((*ReceiptToken)(nil), "types.ReceiptToken") proto.RegisterType((*ReceiptToken)(nil), "types.ReceiptToken")
proto.RegisterType((*ReceiptTokenAmount)(nil), "types.ReceiptTokenAmount")
proto.RegisterType((*LocalToken)(nil), "types.LocalToken") proto.RegisterType((*LocalToken)(nil), "types.LocalToken")
proto.RegisterType((*LocalLogs)(nil), "types.LocalLogs")
proto.RegisterType((*ReqTokens)(nil), "types.ReqTokens") proto.RegisterType((*ReqTokens)(nil), "types.ReqTokens")
proto.RegisterType((*ReplyTokens)(nil), "types.ReplyTokens") proto.RegisterType((*ReplyTokens)(nil), "types.ReplyTokens")
proto.RegisterType((*TokenRecv)(nil), "types.TokenRecv") proto.RegisterType((*TokenRecv)(nil), "types.TokenRecv")
...@@ -1417,72 +1730,83 @@ func init() { ...@@ -1417,72 +1730,83 @@ func init() {
proto.RegisterType((*ReplyAccountTokenAssets)(nil), "types.ReplyAccountTokenAssets") proto.RegisterType((*ReplyAccountTokenAssets)(nil), "types.ReplyAccountTokenAssets")
proto.RegisterType((*ReqAddrTokens)(nil), "types.ReqAddrTokens") proto.RegisterType((*ReqAddrTokens)(nil), "types.ReqAddrTokens")
proto.RegisterType((*ReqTokenTx)(nil), "types.ReqTokenTx") proto.RegisterType((*ReqTokenTx)(nil), "types.ReqTokenTx")
proto.RegisterType((*ReplyTokenLogs)(nil), "types.ReplyTokenLogs")
} }
func init() { proto.RegisterFile("token.proto", fileDescriptor_3aff0bcd502840ab) } func init() { proto.RegisterFile("token.proto", fileDescriptor_3aff0bcd502840ab) }
var fileDescriptor_3aff0bcd502840ab = []byte{ var fileDescriptor_3aff0bcd502840ab = []byte{
// 960 bytes of a gzipped FileDescriptorProto // 1115 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x56, 0xdd, 0x6e, 0xe3, 0x44, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xdd, 0x6a, 0xe3, 0xc6,
0x14, 0x4e, 0xe2, 0xfc, 0xf9, 0x64, 0x9b, 0x6e, 0x86, 0xdd, 0x60, 0x95, 0x15, 0xaa, 0x2c, 0x2e, 0x17, 0xb7, 0x2d, 0x7f, 0x44, 0xc7, 0x89, 0x13, 0xcf, 0x7f, 0x37, 0x7f, 0x91, 0x2e, 0x8b, 0x11,
0x8a, 0x84, 0xaa, 0xaa, 0x15, 0x12, 0x17, 0x48, 0x28, 0x8b, 0xba, 0x1b, 0x7e, 0xb4, 0xa0, 0x21, 0x4b, 0x49, 0xa1, 0x84, 0x90, 0xd0, 0x52, 0x68, 0xa1, 0x38, 0x25, 0xbb, 0xde, 0x76, 0xbb, 0x2d,
0x12, 0xd7, 0x5e, 0xfb, 0xb4, 0xb5, 0x9a, 0xd8, 0xe9, 0x78, 0x92, 0x36, 0x4f, 0xc3, 0x3d, 0x17, 0x53, 0x43, 0xef, 0x0a, 0x5a, 0xe9, 0xc4, 0x11, 0xb1, 0x25, 0x65, 0x34, 0x76, 0xec, 0xa7, 0xe9,
0x3c, 0x02, 0x8f, 0xc2, 0x2d, 0xaf, 0x81, 0xe6, 0xcc, 0x8c, 0x33, 0x93, 0xb4, 0x48, 0x7b, 0x87, 0x7d, 0x2f, 0xfa, 0x08, 0xbd, 0xe8, 0xcb, 0xf4, 0x35, 0xca, 0x9c, 0x19, 0xc9, 0x23, 0x3b, 0x2e,
0xb8, 0xf3, 0xf9, 0xfb, 0xe6, 0x9c, 0xef, 0x7c, 0x1e, 0x1b, 0x06, 0xb2, 0xbc, 0xc5, 0xe2, 0x74, 0xe4, 0xae, 0xf4, 0x4e, 0xe7, 0xeb, 0x37, 0x73, 0xce, 0xf9, 0x9d, 0xe3, 0x31, 0x74, 0x65, 0x7a,
0x29, 0x4a, 0x59, 0xb2, 0x8e, 0xdc, 0x2c, 0xb1, 0x3a, 0x1a, 0x49, 0x91, 0x14, 0x55, 0x92, 0xca, 0x87, 0xc9, 0x59, 0x26, 0x52, 0x99, 0xb2, 0x96, 0x5c, 0x65, 0x98, 0x9f, 0xf4, 0xa5, 0x08, 0x92,
0xbc, 0x34, 0x91, 0xa3, 0x83, 0x24, 0x4d, 0xcb, 0x55, 0x21, 0xb5, 0x19, 0xff, 0x15, 0xc0, 0x60, 0x3c, 0x08, 0x65, 0x9c, 0x1a, 0xcb, 0xc9, 0x41, 0x10, 0x86, 0xe9, 0x3c, 0x91, 0x5a, 0xf4, 0xff,
0xa6, 0x0a, 0x27, 0x94, 0xc4, 0xbe, 0x81, 0x21, 0xe1, 0xfc, 0x2c, 0xf0, 0x5b, 0x81, 0x89, 0xc4, 0x6c, 0x42, 0x77, 0xac, 0x02, 0x87, 0xe4, 0xc4, 0xbe, 0x86, 0x1e, 0xe1, 0xfc, 0x28, 0xf0, 0x1b,
0xa8, 0x79, 0xdc, 0x3c, 0x19, 0x9c, 0xbf, 0x3c, 0x25, 0xc4, 0xd3, 0x99, 0x17, 0x9c, 0x36, 0xf8, 0x81, 0x81, 0x44, 0xaf, 0x3e, 0xa8, 0x9f, 0x76, 0x2f, 0x9e, 0x9f, 0x11, 0xe2, 0xd9, 0xb8, 0x62,
0x4e, 0x3a, 0x9b, 0xc2, 0x88, 0x3c, 0x6f, 0xf2, 0x22, 0xaf, 0x6e, 0x0c, 0x46, 0x8b, 0x30, 0x22, 0x1c, 0xd5, 0xf8, 0x86, 0x3b, 0x1b, 0x41, 0x9f, 0x34, 0xaf, 0xe3, 0x24, 0xce, 0x6f, 0x0d, 0x46,
0x17, 0xc3, 0x8d, 0x4f, 0x1b, 0x7c, 0xbf, 0xa8, 0x46, 0xe2, 0xb8, 0x2e, 0x6f, 0x6d, 0x37, 0xc1, 0x83, 0x30, 0x3c, 0x1b, 0xc3, 0xb6, 0x8f, 0x6a, 0x7c, 0x3b, 0xa8, 0x44, 0xe2, 0xb8, 0x48, 0xef,
0x3e, 0x92, 0x1b, 0xaf, 0x91, 0x5c, 0x27, 0xbb, 0x80, 0x3e, 0x11, 0x71, 0x85, 0x22, 0x6a, 0x7b, 0x8a, 0xdb, 0x38, 0xdb, 0x48, 0xb6, 0xbd, 0x44, 0xb2, 0x95, 0xec, 0x12, 0xf6, 0xa8, 0x10, 0x37,
0xe3, 0x4c, 0xaa, 0x0a, 0x65, 0x35, 0x33, 0xc1, 0x69, 0x83, 0xd7, 0x89, 0xaa, 0xe8, 0x3e, 0x97, 0x28, 0xbc, 0x66, 0x25, 0x9d, 0x61, 0x9e, 0xa3, 0xcc, 0xc7, 0xc6, 0x38, 0xaa, 0xf1, 0xd2, 0x51,
0x37, 0x99, 0x48, 0xee, 0xa3, 0xce, 0x23, 0x45, 0xbf, 0x9a, 0xa0, 0x2a, 0xb2, 0x89, 0xec, 0x0c, 0x05, 0x3d, 0xc4, 0xf2, 0x36, 0x12, 0xc1, 0x83, 0xd7, 0x7a, 0x24, 0xe8, 0x67, 0x63, 0x54, 0x41,
0x7a, 0xd7, 0x58, 0x60, 0x95, 0x57, 0x51, 0x97, 0x6a, 0x5e, 0x78, 0x35, 0x6f, 0x75, 0x6c, 0xda, 0x85, 0x23, 0x3b, 0x87, 0xce, 0x04, 0x13, 0xcc, 0xe3, 0xdc, 0x6b, 0x53, 0xcc, 0xb3, 0x4a, 0xcc,
0xe0, 0x36, 0x8d, 0x5d, 0xc2, 0xd0, 0x1e, 0x39, 0x2b, 0x2f, 0x1f, 0x30, 0x8d, 0xfa, 0x54, 0xf8, 0x1b, 0x6d, 0x1b, 0xd5, 0x78, 0xe1, 0xc6, 0xae, 0xa1, 0x57, 0x1c, 0x39, 0x4e, 0xaf, 0x97, 0x18,
0xc9, 0xa3, 0x1d, 0xea, 0x14, 0xa2, 0xdd, 0xf3, 0xb0, 0x21, 0xb4, 0x66, 0x9b, 0xa8, 0x77, 0xdc, 0x7a, 0x7b, 0x14, 0xf8, 0xd1, 0xa3, 0x37, 0xd4, 0x2e, 0x54, 0xf6, 0x8a, 0x86, 0x9d, 0x83, 0x4b,
0x3c, 0xe9, 0xf0, 0xd6, 0x6c, 0xf3, 0xba, 0x07, 0x9d, 0x75, 0x32, 0x5f, 0x61, 0xfc, 0x67, 0x13, 0x79, 0x7f, 0x1f, 0x27, 0xd2, 0x73, 0x09, 0xe1, 0xc8, 0x2e, 0x92, 0xd2, 0x8f, 0x6a, 0x7c, 0xed,
0x86, 0xfe, 0xd2, 0x18, 0x83, 0x76, 0x91, 0x2c, 0xf4, 0x66, 0x43, 0x4e, 0xcf, 0x6c, 0x0c, 0xdd, 0x54, 0x46, 0x5c, 0xcd, 0x45, 0xe2, 0xc1, 0x76, 0x84, 0xd2, 0x97, 0x11, 0x4a, 0x60, 0x3d, 0x68,
0x6a, 0xb3, 0x78, 0x5f, 0xce, 0x69, 0x57, 0x21, 0x37, 0x16, 0x8b, 0xe1, 0x59, 0x5e, 0x48, 0x51, 0x8c, 0x57, 0x5e, 0x67, 0x50, 0x3f, 0x6d, 0xf1, 0xc6, 0x78, 0x75, 0xd5, 0x81, 0xd6, 0x22, 0x98,
0x66, 0x2b, 0xd2, 0x07, 0xf1, 0x1f, 0x72, 0xcf, 0xc7, 0x5e, 0x40, 0x47, 0x96, 0x32, 0x99, 0x13, 0xce, 0xd1, 0xff, 0xa3, 0x0e, 0xbd, 0x2a, 0x31, 0x18, 0x83, 0x66, 0x12, 0xcc, 0x34, 0x7b, 0x5c,
0xb7, 0x01, 0xd7, 0x86, 0xf2, 0x2e, 0x45, 0x9e, 0x22, 0x91, 0x17, 0x70, 0x6d, 0x28, 0x6f, 0x79, 0x4e, 0xdf, 0xec, 0x18, 0xda, 0xf9, 0x6a, 0xf6, 0x21, 0x9d, 0x12, 0x1f, 0x5c, 0x6e, 0x24, 0xe6,
0x5f, 0xa0, 0x20, 0x7a, 0x42, 0xae, 0x0d, 0x76, 0x04, 0xfd, 0x34, 0x91, 0x78, 0x5d, 0x0a, 0x3b, 0xc3, 0x7e, 0x9c, 0x48, 0x91, 0x46, 0x73, 0xe2, 0x20, 0xf5, 0xd8, 0xe5, 0x15, 0x1d, 0x7b, 0x06,
0x43, 0x6d, 0xc7, 0x13, 0x18, 0xed, 0x09, 0xc6, 0x69, 0xb7, 0xe9, 0xb5, 0x5b, 0xc3, 0xb7, 0x1c, 0x2d, 0x99, 0xca, 0x60, 0x4a, 0xfd, 0x73, 0xb8, 0x16, 0x94, 0x36, 0x13, 0x71, 0x88, 0xd4, 0x20,
0xf8, 0x1a, 0xc2, 0x13, 0xc5, 0x87, 0x41, 0xfc, 0xdd, 0x84, 0x0e, 0x61, 0xfc, 0x07, 0xd9, 0x8b, 0x87, 0x6b, 0x41, 0x69, 0xd3, 0x87, 0x04, 0x05, 0xb5, 0xc0, 0xe5, 0x5a, 0x60, 0x27, 0xb0, 0x17,
0xa0, 0x97, 0xaa, 0x99, 0x4a, 0x41, 0xe4, 0x85, 0xdc, 0x9a, 0xd4, 0x97, 0x4c, 0xe4, 0xaa, 0x22, 0x06, 0x12, 0x27, 0xa9, 0x28, 0x72, 0x28, 0x65, 0x7f, 0x08, 0xfd, 0x2d, 0x52, 0x5a, 0xd7, 0xad,
0x51, 0x75, 0xb8, 0xb1, 0x3c, 0xbe, 0xc3, 0x1d, 0xbe, 0x67, 0xf0, 0x8c, 0x63, 0x8a, 0xf9, 0x52, 0x57, 0xae, 0x5b, 0xc2, 0x37, 0x2c, 0xf8, 0x12, 0xa2, 0x42, 0xbc, 0xa7, 0x41, 0x7c, 0x09, 0x6e,
0xea, 0x79, 0x3f, 0x88, 0x27, 0xe7, 0xc4, 0xc0, 0x3d, 0x31, 0xfe, 0xbd, 0x0d, 0xf0, 0x63, 0x99, 0xd9, 0xab, 0x9d, 0xa1, 0xc7, 0xd0, 0x0e, 0x66, 0x6a, 0x80, 0x29, 0xd6, 0xe1, 0x46, 0x2a, 0x83,
0x26, 0xf3, 0xff, 0x0f, 0x89, 0x9f, 0xc1, 0x01, 0xa5, 0x60, 0x36, 0xc5, 0xfc, 0xfa, 0x46, 0x12, 0xa9, 0x53, 0x4f, 0x0d, 0xfe, 0xab, 0x0e, 0x2d, 0x8a, 0xfe, 0x17, 0xf6, 0xcd, 0x83, 0x4e, 0xa8,
0x93, 0x01, 0xf7, 0x9d, 0xec, 0x18, 0x06, 0xc6, 0x31, 0xcb, 0x17, 0x18, 0x01, 0xe5, 0xb8, 0x2e, 0xaa, 0x99, 0x0a, 0x6a, 0x9b, 0xcb, 0x0b, 0x91, 0xee, 0x25, 0x03, 0x39, 0xcf, 0x69, 0x64, 0x5a,
0x76, 0x06, 0x1f, 0x2d, 0x05, 0x2e, 0x93, 0xfa, 0x52, 0xd5, 0x68, 0x03, 0xca, 0x7c, 0x2c, 0xc4, 0xdc, 0x48, 0x95, 0x4e, 0xbb, 0x1b, 0x9d, 0x1e, 0xc3, 0x3e, 0xc7, 0x10, 0xe3, 0x4c, 0xea, 0x7c,
0xbe, 0x80, 0x91, 0xe7, 0x26, 0xe4, 0x67, 0x94, 0xbf, 0x1f, 0x60, 0xaf, 0x20, 0x5c, 0x0a, 0x4c, 0x9f, 0xd4, 0x21, 0xeb, 0x44, 0xc7, 0x3e, 0xd1, 0xff, 0x05, 0x98, 0x8d, 0x3a, 0xa4, 0xaa, 0xb2,
0xf3, 0x4a, 0x91, 0x77, 0x40, 0x23, 0x6c, 0x1d, 0xec, 0x14, 0x18, 0x91, 0x55, 0xdf, 0x30, 0xf9, 0x01, 0x34, 0x33, 0x81, 0x0b, 0xb3, 0x41, 0xf7, 0x2b, 0x3b, 0x8b, 0x2c, 0xec, 0x63, 0xe8, 0x84,
0x02, 0xab, 0x68, 0x48, 0x60, 0x8f, 0x44, 0xd4, 0xd4, 0x82, 0x5e, 0x23, 0x3b, 0xf5, 0xa1, 0x9e, 0x73, 0x21, 0xd0, 0x34, 0x64, 0xd3, 0xa9, 0x30, 0xfa, 0xbf, 0x35, 0x01, 0xde, 0xa5, 0x61, 0x30,
0xda, 0x73, 0xaa, 0xa9, 0x8d, 0x83, 0x7a, 0x7b, 0xae, 0xa7, 0x76, 0x5c, 0x9e, 0x04, 0x47, 0x3b, 0xfd, 0xef, 0x34, 0xe9, 0x15, 0x1c, 0x90, 0x0b, 0x46, 0x23, 0x8c, 0x27, 0xb7, 0x7a, 0x69, 0x39,
0x12, 0xbc, 0x87, 0x90, 0xe3, 0x1d, 0x29, 0x85, 0xb4, 0x7a, 0xb7, 0x42, 0xb1, 0x99, 0xcc, 0xb5, 0xbc, 0xaa, 0x64, 0x03, 0xe8, 0x1a, 0xc5, 0x38, 0x9e, 0x21, 0xad, 0x29, 0x87, 0xdb, 0x2a, 0x76,
0x02, 0xfb, 0xbc, 0xb6, 0x9d, 0xd5, 0xb4, 0xbc, 0xd5, 0x8c, 0xa1, 0x4b, 0x5f, 0x01, 0xa5, 0xc2, 0x0e, 0xff, 0xcb, 0x04, 0x66, 0x41, 0xf9, 0x93, 0xa4, 0xd1, 0xba, 0xe4, 0xf9, 0x98, 0x89, 0x7d,
0x40, 0x49, 0x49, 0x5b, 0xec, 0x53, 0x00, 0x2d, 0xaa, 0x9f, 0x8a, 0xf9, 0x86, 0xb4, 0xd2, 0xe7, 0x0a, 0xfd, 0x8a, 0x9a, 0x90, 0xf7, 0xc9, 0x7f, 0xdb, 0xc0, 0x5e, 0x80, 0x9b, 0x09, 0x0c, 0xe3,
0x8e, 0x27, 0xfe, 0x0a, 0x06, 0x1c, 0x97, 0xf3, 0x8d, 0x39, 0xfa, 0xf3, 0x1a, 0xa6, 0x79, 0x1c, 0x5c, 0x15, 0xef, 0x80, 0x52, 0x58, 0x2b, 0xd8, 0x19, 0x30, 0x2a, 0x56, 0xb9, 0x9f, 0xe3, 0x19,
0x9c, 0x0c, 0xce, 0x47, 0xe6, 0x4e, 0xde, 0x0a, 0xd9, 0x22, 0xc7, 0x5f, 0x42, 0x68, 0xae, 0x98, 0xe6, 0x5e, 0x8f, 0xc0, 0x1e, 0xb1, 0xa8, 0xac, 0x05, 0x2d, 0x88, 0x22, 0xeb, 0x43, 0x9d, 0x75,
0x74, 0xad, 0xd5, 0x78, 0x8b, 0x85, 0x91, 0xb7, 0x36, 0x94, 0xe6, 0x05, 0xa6, 0x6b, 0x6a, 0x35, 0x45, 0xa9, 0xb2, 0x36, 0x0a, 0xba, 0xdb, 0x91, 0xce, 0xda, 0x52, 0x55, 0x28, 0xde, 0xdf, 0xa0,
0xe0, 0xf4, 0x1c, 0x7f, 0x0f, 0x63, 0x3a, 0x70, 0x92, 0x65, 0x42, 0x95, 0xbe, 0x29, 0x85, 0x39, 0xf8, 0x1c, 0x5c, 0xe2, 0xca, 0xbb, 0x74, 0x92, 0xef, 0xe4, 0xb7, 0x07, 0x1d, 0xb9, 0x7c, 0x9b,
0xfb, 0x0c, 0x40, 0x5a, 0x40, 0x7b, 0xfe, 0x73, 0xff, 0xb3, 0x97, 0xae, 0xb9, 0x93, 0x13, 0xe7, 0x44, 0xb8, 0x34, 0x7c, 0x29, 0x44, 0xf6, 0x12, 0x40, 0x3f, 0x18, 0xc6, 0xab, 0x0c, 0x0d, 0xcf,
0x70, 0x68, 0x59, 0x7b, 0x9d, 0xcc, 0x93, 0x22, 0xa5, 0xd5, 0x27, 0x59, 0x26, 0xb0, 0xaa, 0x50, 0x2d, 0x8d, 0x42, 0x94, 0xcb, 0x51, 0x90, 0xdf, 0x12, 0x5b, 0x5c, 0x6e, 0x24, 0xff, 0x01, 0x5c,
0x63, 0x84, 0x7c, 0xeb, 0x50, 0x4b, 0xa2, 0xf2, 0x5f, 0xdc, 0xb7, 0xce, 0x75, 0x29, 0x1e, 0xf1, 0x8e, 0xf7, 0x44, 0x50, 0x1a, 0xc1, 0xfb, 0x39, 0x8a, 0xd5, 0x70, 0xaa, 0x0f, 0xde, 0xe3, 0xa5,
0x01, 0x53, 0x14, 0xe6, 0xa5, 0x33, 0x56, 0xfc, 0x1d, 0xbc, 0xe4, 0x78, 0x37, 0xd1, 0x7f, 0x12, 0x6c, 0x31, 0xa2, 0x51, 0x61, 0x84, 0x02, 0xa6, 0x68, 0xcf, 0x19, 0x38, 0x04, 0xac, 0xb1, 0x5e,
0xfa, 0xf7, 0x81, 0x3e, 0x53, 0xea, 0x2d, 0x32, 0xf8, 0x66, 0x76, 0x6b, 0x3a, 0x50, 0x2d, 0x0f, 0x02, 0xe8, 0x4b, 0xff, 0x90, 0x4c, 0x57, 0x74, 0xe8, 0x1e, 0xb7, 0x34, 0xfe, 0x17, 0xd0, 0xe5,
0xea, 0x1d, 0xc0, 0x16, 0xe0, 0xc9, 0xcb, 0xe6, 0x04, 0x7a, 0xe6, 0xbf, 0xc5, 0xfc, 0x4b, 0x0c, 0x98, 0x4d, 0x57, 0xe6, 0xe8, 0x4f, 0x4a, 0x98, 0xfa, 0xc0, 0x39, 0xed, 0x5e, 0xf4, 0xcd, 0x48,
0xed, 0xe7, 0x51, 0x7b, 0xb9, 0x0d, 0xc7, 0xef, 0xe0, 0x63, 0xcd, 0xe8, 0x7e, 0x73, 0x17, 0x66, 0xad, 0xe7, 0xa7, 0x40, 0xf6, 0x3f, 0x33, 0x3b, 0x93, 0x63, 0xb8, 0xd0, 0x43, 0x70, 0x87, 0x89,
0x5e, 0x6d, 0xee, 0xec, 0x74, 0x9b, 0xc8, 0xdd, 0xac, 0xf8, 0xb7, 0x26, 0x1c, 0xa8, 0x59, 0xb3, 0x29, 0x94, 0x16, 0xd4, 0xa8, 0x09, 0x0c, 0x17, 0x66, 0x5f, 0xd2, 0xb7, 0xff, 0x2d, 0x1c, 0xd3,
0xcc, 0x6e, 0x86, 0x41, 0x5b, 0x0d, 0x65, 0xef, 0x2e, 0xf5, 0xfc, 0xa4, 0x10, 0x6b, 0x25, 0x68, 0x81, 0xc3, 0x28, 0x12, 0x2a, 0xf4, 0x75, 0x2a, 0xcc, 0xd9, 0xe7, 0x00, 0xb2, 0x00, 0x2c, 0xce,
0x1d, 0x1a, 0x25, 0xbc, 0x82, 0x30, 0xcb, 0x05, 0xea, 0xeb, 0xac, 0xad, 0xdf, 0xc8, 0xda, 0xa1, 0x3f, 0xaa, 0xbe, 0x55, 0xc2, 0x05, 0xb7, 0x7c, 0xfc, 0x18, 0x0e, 0x8b, 0xaa, 0x5d, 0x05, 0xd3,
0x6a, 0xf4, 0xa4, 0x1d, 0x8a, 0x68, 0x43, 0x31, 0x7b, 0x25, 0xca, 0xc5, 0x0f, 0xb8, 0x31, 0xf7, 0x20, 0x09, 0x89, 0x71, 0x41, 0x14, 0x09, 0xcc, 0x73, 0xd4, 0x18, 0x2e, 0x5f, 0x2b, 0x14, 0x37,
0x96, 0x35, 0xe3, 0x3f, 0x9a, 0x00, 0x76, 0xf1, 0xb3, 0x87, 0x27, 0x29, 0x64, 0xd0, 0xbe, 0x9a, 0x28, 0xfc, 0x27, 0x7b, 0xd8, 0x6d, 0x95, 0xaa, 0x23, 0x2e, 0x31, 0x44, 0x61, 0x66, 0xdd, 0x48,
0x27, 0xd7, 0xa6, 0x41, 0x7a, 0xde, 0x1e, 0x15, 0xb8, 0x47, 0xfd, 0x7b, 0x7b, 0x63, 0xe8, 0xde, 0xfe, 0x5b, 0x78, 0xce, 0xf1, 0x7e, 0xa8, 0x9f, 0x7f, 0x7a, 0x4f, 0xd1, 0xdb, 0x42, 0x71, 0xc1,
0xe8, 0x37, 0x5f, 0xdf, 0xaa, 0xc6, 0x52, 0x58, 0x79, 0x91, 0xe1, 0x03, 0xb5, 0x17, 0x70, 0x6d, 0xe0, 0x9b, 0xdc, 0x0b, 0xd1, 0x82, 0x6a, 0x54, 0xa0, 0xde, 0x03, 0xac, 0x01, 0x76, 0x72, 0xec,
0xd4, 0x64, 0xf5, 0xb6, 0x64, 0x9d, 0x5f, 0x1a, 0x52, 0xd8, 0xd7, 0x70, 0xf8, 0x16, 0xa5, 0xa7, 0x14, 0x3a, 0xe6, 0xb1, 0x69, 0xb6, 0x5b, 0xaf, 0x78, 0xd3, 0x68, 0x2d, 0x2f, 0xcc, 0xfe, 0x7b,
0xd8, 0xb1, 0x59, 0xc7, 0x8e, 0x92, 0x8f, 0x0e, 0xfd, 0x7d, 0x57, 0x71, 0xe3, 0x7d, 0x97, 0xfe, 0xf8, 0xbf, 0xae, 0xe8, 0xf6, 0xe5, 0x2e, 0x4d, 0xbe, 0x5a, 0xdc, 0xe8, 0xe9, 0xda, 0x91, 0xdb,
0x60, 0x2f, 0xfe, 0x09, 0x00, 0x00, 0xff, 0xff, 0x84, 0xd1, 0x60, 0x7f, 0xf9, 0x0a, 0x00, 0x00, 0x5e, 0xfe, 0xaf, 0x75, 0x38, 0x50, 0xb9, 0x46, 0x51, 0xd1, 0x19, 0x06, 0x4d, 0x95, 0x54, 0xb1,
0x32, 0xd5, 0xf7, 0x4e, 0x22, 0x96, 0x4c, 0xd0, 0x3c, 0x34, 0x4c, 0x78, 0x01, 0x6e, 0x14, 0x0b,
0xd4, 0x5b, 0xb4, 0xa9, 0x17, 0x41, 0xa9, 0x50, 0x31, 0x3a, 0xd3, 0x16, 0x59, 0xb4, 0xa0, 0x2a,
0x7b, 0x23, 0xd2, 0xd9, 0x77, 0xb8, 0x32, 0xeb, 0xb2, 0x10, 0xfd, 0xdf, 0xeb, 0x00, 0x45, 0xe3,
0xc7, 0xcb, 0x9d, 0x25, 0x64, 0xd0, 0xbc, 0x99, 0x06, 0x13, 0x73, 0x41, 0xfa, 0x5e, 0x1f, 0xe5,
0xd8, 0x47, 0xfd, 0xf3, 0xf5, 0x8e, 0xa1, 0x7d, 0xab, 0x17, 0x8e, 0x5e, 0xe6, 0x46, 0x52, 0x58,
0x31, 0x2d, 0x81, 0xb6, 0xde, 0xf1, 0x24, 0x94, 0xc5, 0xea, 0xac, 0x8b, 0xe5, 0x7f, 0x0e, 0xbd,
0xf5, 0x94, 0xd1, 0x6a, 0x79, 0x05, 0xcd, 0x69, 0x3a, 0xd9, 0xa4, 0x79, 0xb9, 0x7a, 0x38, 0x59,
0x2f, 0xae, 0x4d, 0x31, 0xd9, 0x57, 0x70, 0xf8, 0x06, 0x65, 0x85, 0xe9, 0xc7, 0x26, 0x66, 0x63,
0x02, 0x4e, 0x0e, 0xab, 0x3c, 0xc9, 0xfd, 0xda, 0x87, 0x36, 0xfd, 0x5d, 0xb9, 0xfc, 0x3b, 0x00,
0x00, 0xff, 0xff, 0xe2, 0xae, 0x58, 0x34, 0xe6, 0x0c, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
......
...@@ -57,6 +57,8 @@ func (t *TokenType) GetTypeMap() map[string]int32 { ...@@ -57,6 +57,8 @@ func (t *TokenType) GetTypeMap() map[string]int32 {
"TokenFinishCreate": TokenActionFinishCreate, "TokenFinishCreate": TokenActionFinishCreate,
"TokenRevokeCreate": TokenActionRevokeCreate, "TokenRevokeCreate": TokenActionRevokeCreate,
"TransferToExec": TokenActionTransferToExec, "TransferToExec": TokenActionTransferToExec,
"TokenMint": TokenActionMint,
"TokenBurn": TokenActionBurn,
} }
} }
...@@ -75,6 +77,8 @@ func (t *TokenType) GetLogMap() map[int64]*types.LogInfo { ...@@ -75,6 +77,8 @@ func (t *TokenType) GetLogMap() map[int64]*types.LogInfo {
TyLogPreCreateToken: {Ty: reflect.TypeOf(ReceiptToken{}), Name: "LogPreCreateToken"}, TyLogPreCreateToken: {Ty: reflect.TypeOf(ReceiptToken{}), Name: "LogPreCreateToken"},
TyLogFinishCreateToken: {Ty: reflect.TypeOf(ReceiptToken{}), Name: "LogFinishCreateToken"}, TyLogFinishCreateToken: {Ty: reflect.TypeOf(ReceiptToken{}), Name: "LogFinishCreateToken"},
TyLogRevokeCreateToken: {Ty: reflect.TypeOf(ReceiptToken{}), Name: "LogRevokeCreateToken"}, TyLogRevokeCreateToken: {Ty: reflect.TypeOf(ReceiptToken{}), Name: "LogRevokeCreateToken"},
TyLogTokenMint: {Ty: reflect.TypeOf(ReceiptTokenAmount{}), Name: "LogMintToken"},
TyLogTokenBurn: {Ty: reflect.TypeOf(ReceiptTokenAmount{}), Name: "LogBurnToken"},
} }
} }
......
package init package init
import ( import (
_ "github.com/33cn/plugin/plugin/store/kvdb" //auto gen _ "github.com/33cn/plugin/plugin/store/kvdb" //auto gen
_ "github.com/33cn/plugin/plugin/store/kvmvcc" //auto gen _ "github.com/33cn/plugin/plugin/store/kvmvcc" //auto gen
_ "github.com/33cn/plugin/plugin/store/mpt" //auto gen _ "github.com/33cn/plugin/plugin/store/kvmvccmavl" //auto gen
_ "github.com/33cn/plugin/plugin/store/mpt" //auto gen
) )
// 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 kvmvccmavl kvmvcc+mavl接口
package kvmvccmavl
import (
"bytes"
"errors"
"fmt"
"sync"
"sync/atomic"
"time"
dbm "github.com/33cn/chain33/common/db"
clog "github.com/33cn/chain33/common/log"
log "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/queue"
drivers "github.com/33cn/chain33/system/store"
"github.com/33cn/chain33/types"
"github.com/hashicorp/golang-lru"
)
var (
kmlog = log.New("module", "kvmvccMavl")
// ErrStateHashLost ...
ErrStateHashLost = errors.New("ErrStateHashLost")
kvmvccMavlFork int64 = 200 * 10000
isDelMavlData = false
delMavlDataHeight = kvmvccMavlFork + 10000
delMavlDataState int32
wg sync.WaitGroup
quit bool
)
const (
cacheSize = 2048 //可以缓存2048个roothash, height对
batchDataSize = 1024 * 1024 * 1
delMavlStateStart = 1
delMavlStateEnd = 0
)
// SetLogLevel set log level
func SetLogLevel(level string) {
clog.SetLogLevel(level)
}
// DisableLog disable log output
func DisableLog() {
kmlog.SetHandler(log.DiscardHandler())
}
func init() {
drivers.Reg("kvmvccmavl", New)
}
// KVmMavlStore provide kvmvcc and mavl store interface implementation
type KVmMavlStore struct {
*drivers.BaseStore
*KVMVCCStore
*MavlStore
cache *lru.Cache
}
type subKVMVCCConfig struct {
EnableMVCCIter bool `json:"enableMVCCIter"`
EnableMavlPrune bool `json:"enableMavlPrune"`
PruneHeight int32 `json:"pruneHeight"`
}
type subMavlConfig struct {
EnableMavlPrefix bool `json:"enableMavlPrefix"`
EnableMVCC bool `json:"enableMVCC"`
EnableMavlPrune bool `json:"enableMavlPrune"`
PruneHeight int32 `json:"pruneHeight"`
}
type subConfig struct {
EnableMVCCIter bool `json:"enableMVCCIter"`
EnableMavlPrefix bool `json:"enableMavlPrefix"`
EnableMVCC bool `json:"enableMVCC"`
EnableMavlPrune bool `json:"enableMavlPrune"`
PruneHeight int32 `json:"pruneHeight"`
}
// New construct KVMVCCStore module
func New(cfg *types.Store, sub []byte) queue.Module {
bs := drivers.NewBaseStore(cfg)
var kvms *KVmMavlStore
var subcfg subConfig
var subKVMVCCcfg subKVMVCCConfig
var subMavlcfg subMavlConfig
if sub != nil {
types.MustDecode(sub, &subcfg)
subKVMVCCcfg.EnableMVCCIter = subcfg.EnableMVCCIter
subKVMVCCcfg.EnableMavlPrune = subcfg.EnableMavlPrune
subKVMVCCcfg.PruneHeight = subcfg.PruneHeight
subMavlcfg.EnableMavlPrefix = subcfg.EnableMavlPrefix
subMavlcfg.EnableMVCC = subcfg.EnableMVCC
subMavlcfg.EnableMavlPrune = subcfg.EnableMavlPrune
subMavlcfg.PruneHeight = subcfg.PruneHeight
}
cache, err := lru.New(cacheSize)
if err != nil {
panic("new KVmMavlStore fail")
}
kvms = &KVmMavlStore{bs, NewKVMVCC(&subKVMVCCcfg, bs.GetDB()),
NewMavl(&subMavlcfg, bs.GetDB()), cache}
// 查询是否已经删除mavl
_, err = bs.GetDB().Get(genDelMavlKey(mvccPrefix))
if err == nil {
isDelMavlData = true
}
bs.SetChild(kvms)
return kvms
}
// Close the KVmMavlStore module
func (kvmMavls *KVmMavlStore) Close() {
quit = true
wg.Wait()
kvmMavls.KVMVCCStore.Close()
kvmMavls.MavlStore.Close()
kvmMavls.BaseStore.Close()
kmlog.Info("store kvmMavls closed")
}
// Set kvs with statehash to KVmMavlStore
func (kvmMavls *KVmMavlStore) Set(datas *types.StoreSet, sync bool) ([]byte, error) {
if datas.Height < kvmvccMavlFork {
hash, err := kvmMavls.MavlStore.Set(datas, sync)
if err != nil {
return hash, err
}
_, err = kvmMavls.KVMVCCStore.Set(datas, hash, sync)
if err != nil {
return hash, err
}
if err == nil {
kvmMavls.cache.Add(string(hash), datas.Height)
}
return hash, err
}
// 仅仅做kvmvcc
hash, err := kvmMavls.KVMVCCStore.Set(datas, nil, sync)
if err == nil {
kvmMavls.cache.Add(string(hash), datas.Height)
}
// 删除Mavl数据
if datas.Height > delMavlDataHeight && !isDelMavlData && !isDelMavling() {
wg.Add(1)
go DelMavl(kvmMavls.GetDB())
}
return hash, err
}
// Get kvs with statehash from KVmMavlStore
func (kvmMavls *KVmMavlStore) Get(datas *types.StoreGet) [][]byte {
return kvmMavls.KVMVCCStore.Get(datas)
}
// MemSet set kvs to the mem of KVmMavlStore module and return the StateHash
func (kvmMavls *KVmMavlStore) MemSet(datas *types.StoreSet, sync bool) ([]byte, error) {
if datas.Height < kvmvccMavlFork {
hash, err := kvmMavls.MavlStore.MemSet(datas, sync)
if err != nil {
return hash, err
}
_, err = kvmMavls.KVMVCCStore.MemSet(datas, hash, sync)
if err != nil {
return hash, err
}
if err == nil {
kvmMavls.cache.Add(string(hash), datas.Height)
}
return hash, err
}
// 仅仅做kvmvcc
hash, err := kvmMavls.KVMVCCStore.MemSet(datas, nil, sync)
if err == nil {
kvmMavls.cache.Add(string(hash), datas.Height)
}
// 删除Mavl数据
if datas.Height > delMavlDataHeight && !isDelMavlData && !isDelMavling() {
wg.Add(1)
go DelMavl(kvmMavls.GetDB())
}
return hash, err
}
// Commit kvs in the mem of KVmMavlStore module to state db and return the StateHash
func (kvmMavls *KVmMavlStore) Commit(req *types.ReqHash) ([]byte, error) {
if value, ok := kvmMavls.cache.Get(string(req.Hash)); ok {
if value.(int64) < kvmvccMavlFork {
hash, err := kvmMavls.MavlStore.Commit(req)
if err != nil {
return hash, err
}
_, err = kvmMavls.KVMVCCStore.Commit(req)
return hash, err
}
return kvmMavls.KVMVCCStore.Commit(req)
}
return kvmMavls.KVMVCCStore.Commit(req)
}
// Rollback kvs in the mem of KVmMavlStore module and return the StateHash
func (kvmMavls *KVmMavlStore) Rollback(req *types.ReqHash) ([]byte, error) {
if value, ok := kvmMavls.cache.Get(string(req.Hash)); ok {
if value.(int64) < kvmvccMavlFork {
hash, err := kvmMavls.MavlStore.Rollback(req)
if err != nil {
return hash, err
}
_, err = kvmMavls.KVMVCCStore.Rollback(req)
return hash, err
}
return kvmMavls.KVMVCCStore.Rollback(req)
}
return kvmMavls.KVMVCCStore.Rollback(req)
}
// IterateRangeByStateHash travel with Prefix by StateHash to get the latest version kvs.
func (kvmMavls *KVmMavlStore) IterateRangeByStateHash(statehash []byte, start []byte, end []byte, ascending bool, fn func(key, value []byte) bool) {
if value, ok := kvmMavls.cache.Get(string(statehash)); ok {
if value.(int64) < kvmvccMavlFork {
kvmMavls.MavlStore.IterateRangeByStateHash(statehash, start, end, ascending, fn)
return
}
kvmMavls.KVMVCCStore.IterateRangeByStateHash(statehash, start, end, ascending, fn)
return
}
kvmMavls.KVMVCCStore.IterateRangeByStateHash(statehash, start, end, ascending, fn)
}
// ProcEvent handles supported events
func (kvmMavls *KVmMavlStore) ProcEvent(msg *queue.Message) {
msg.ReplyErr("KVmMavlStore", types.ErrActionNotSupport)
}
// Del set kvs to nil with StateHash
func (kvmMavls *KVmMavlStore) Del(req *types.StoreDel) ([]byte, error) {
if req.Height < kvmvccMavlFork {
hash, err := kvmMavls.MavlStore.Del(req)
if err != nil {
return hash, err
}
_, err = kvmMavls.KVMVCCStore.Del(req)
if err != nil {
return hash, err
}
if err == nil {
kvmMavls.cache.Remove(string(req.StateHash))
}
return hash, err
}
// 仅仅做kvmvcc
hash, err := kvmMavls.KVMVCCStore.Del(req)
if err == nil {
kvmMavls.cache.Remove(string(req.StateHash))
}
return hash, err
}
// DelMavl 数据库中mavl数据清除
// 达到kvmvccMavlFork + 100000 后触发清除
func DelMavl(db dbm.DB) {
defer wg.Done()
setDelMavl(delMavlStateStart)
defer setDelMavl(delMavlStateEnd)
isDel := delMavlData(db)
if isDel {
isDelMavlData = true
kmlog.Info("DelMavl success")
}
}
func delMavlData(db dbm.DB) bool {
it := db.Iterator(nil, nil, true)
defer it.Close()
batch := db.NewBatch(true)
for it.Rewind(); it.Valid(); it.Next() {
if quit {
return false
}
if !bytes.HasPrefix(it.Key(), mvccPrefix) { // 将非mvcc的mavl数据全部删除
batch.Delete(it.Key())
if batch.ValueSize() > batchDataSize {
batch.Write()
batch.Reset()
time.Sleep(time.Millisecond * 100)
}
}
}
batch.Set(genDelMavlKey(mvccPrefix), []byte(""))
batch.Write()
return true
}
func genDelMavlKey(prefix []byte) []byte {
delMavl := "--delMavlData--"
return []byte(fmt.Sprintf("%s%s", string(prefix), delMavl))
}
func isDelMavling() bool {
return atomic.LoadInt32(&delMavlDataState) == 1
}
func setDelMavl(state int32) {
atomic.StoreInt32(&delMavlDataState, state)
}
// 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 kvmvccmavl
import (
"encoding/json"
"io/ioutil"
"os"
"testing"
"time"
"fmt"
"bytes"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
drivers "github.com/33cn/chain33/system/store"
"github.com/33cn/chain33/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const MaxKeylenth int = 64
func newStoreCfg(dir string) *types.Store {
return &types.Store{Name: "kvmvccMavl_test", Driver: "leveldb", DbPath: dir, DbCache: 100}
}
func newStoreCfgIter(dir string) (*types.Store, []byte) {
return &types.Store{Name: "kvmvccMavl_test", Driver: "leveldb", DbPath: dir, DbCache: 100}, enableConfig()
}
func TestKvmvccMavlNewClose(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(t, store)
store.Close()
}
func TestKvmvccMavlSetGet(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(t, store)
kvmvccMavlFork = 50
defer func() {
kvmvccMavlFork = 200 * 10000
}()
hash := drivers.EmptyRoot[:]
for i := 0; i < 100; i++ {
var kvs []*types.KeyValue
kvs = append(kvs, &types.KeyValue{Key: []byte(fmt.Sprintf("k%d", i)), Value: []byte(fmt.Sprintf("v%d", i))})
kvs = append(kvs, &types.KeyValue{Key: []byte(fmt.Sprintf("key%d", i)), Value: []byte(fmt.Sprintf("value%d", i))})
datas := &types.StoreSet{
StateHash: hash,
KV: kvs,
Height: int64(i)}
hash, err = store.Set(datas, true)
assert.Nil(t, err)
keys := [][]byte{[]byte(fmt.Sprintf("k%d", i)), []byte(fmt.Sprintf("key%d", i))}
get := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get)
assert.Len(t, values, 2)
assert.Equal(t, []byte(fmt.Sprintf("v%d", i)), values[0])
assert.Equal(t, []byte(fmt.Sprintf("value%d", i)), values[1])
}
}
func TestKvmvccMavlMemSet(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(t, store)
kvmvccMavlFork = 50
defer func() {
kvmvccMavlFork = 200 * 10000
}()
hash := drivers.EmptyRoot[:]
for i := 0; i < 100; i++ {
var kvs []*types.KeyValue
kvs = append(kvs, &types.KeyValue{Key: []byte(fmt.Sprintf("k%d", i)), Value: []byte(fmt.Sprintf("v%d", i))})
kvs = append(kvs, &types.KeyValue{Key: []byte(fmt.Sprintf("key%d", i)), Value: []byte(fmt.Sprintf("value%d", i))})
datas := &types.StoreSet{
StateHash: hash,
KV: kvs,
Height: int64(i)}
hash, err = store.MemSet(datas, true)
assert.Nil(t, err)
actHash, _ := store.Commit(&types.ReqHash{Hash: hash})
assert.Equal(t, hash, actHash)
keys := [][]byte{[]byte(fmt.Sprintf("k%d", i)), []byte(fmt.Sprintf("key%d", i))}
get := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get)
assert.Len(t, values, 2)
assert.Equal(t, []byte(fmt.Sprintf("v%d", i)), values[0])
assert.Equal(t, []byte(fmt.Sprintf("value%d", i)), values[1])
}
notExistHash, _ := store.Commit(&types.ReqHash{Hash: drivers.EmptyRoot[:]})
assert.Nil(t, notExistHash)
}
func TestKvmvccMavlCommit(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(t, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
// 设置分叉高度
forkHeight := 100
kvmvccMavlFork = int64(forkHeight)
defer func() {
kvmvccMavlFork = 200 * 10000
}()
frontHash := make([]byte, 0, 32)
var hash []byte
for i := 0; i < 200; i++ {
datas.Height = int64(i)
hash, err = store.MemSet(datas, true)
assert.Nil(t, err)
req := &types.ReqHash{
Hash: hash,
}
if i+1 == forkHeight {
frontHash = append(frontHash, hash...)
}
_, err = store.Commit(req)
assert.NoError(t, err, "NoError")
datas.StateHash = hash
}
if len(frontHash) > 0 {
get := &types.StoreGet{StateHash: frontHash, Keys: keys}
values := store.Get(get)
require.Equal(t, len(values), len(keys))
for i := range keys {
require.Equal(t, kv[i].Value, values[i])
}
}
if len(hash) > 0 {
get := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get)
require.Equal(t, len(values), len(keys))
for i := range keys {
require.Equal(t, kv[i].Value, values[i])
}
}
}
func TestKvmvccMavlRollback(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(t, store)
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
keys := [][]byte{[]byte("mk1"), []byte("mk2")}
get := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get)
assert.Len(t, values, 2)
actHash, _ := store.Rollback(&types.ReqHash{Hash: hash})
assert.Equal(t, hash, actHash)
notExistHash, err := store.Rollback(&types.ReqHash{Hash: drivers.EmptyRoot[:]})
assert.Nil(t, notExistHash)
assert.Equal(t, types.ErrHashNotFound.Error(), err.Error())
// 分叉之后
kvmvccMavlFork = 1
defer func() {
kvmvccMavlFork = 200 * 10000
}()
hash, err = store.MemSet(datas, true)
assert.Nil(t, err)
actHash, _ = store.Commit(&types.ReqHash{Hash: hash})
assert.Equal(t, hash, actHash)
var kv1 []*types.KeyValue
kv1 = append(kv1, &types.KeyValue{Key: []byte("mk3"), Value: []byte("v3")})
kv1 = append(kv1, &types.KeyValue{Key: []byte("mk4"), Value: []byte("v4")})
datas1 := &types.StoreSet{
StateHash: hash,
KV: kv1,
Height: 1}
hash1, err := store.MemSet(datas1, true)
assert.Nil(t, err)
keys1 := [][]byte{[]byte("mk3"), []byte("mk4")}
get1 := &types.StoreGet{StateHash: hash1, Keys: keys1}
values1 := store.Get(get1)
assert.Len(t, values1, 2)
actHash, _ = store.Rollback(&types.ReqHash{Hash: hash1})
assert.Equal(t, hash1, actHash)
notExistHash, err = store.Rollback(&types.ReqHash{Hash: drivers.EmptyRoot[:]})
assert.Nil(t, notExistHash)
assert.Equal(t, types.ErrHashNotFound.Error(), err.Error())
}
func TestKvmvccdbRollbackBatch(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(t, store)
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v1")})
kv = append(kv, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v2")})
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
var kvset []*types.KeyValue
req := &types.ReqHash{Hash: hash}
hash1 := make([]byte, len(hash))
copy(hash1, hash)
store.Commit(req)
// 设置分叉高度
kvmvccMavlFork = 50
defer func() {
kvmvccMavlFork = 200 * 10000
}()
for i := 1; i <= 202; i++ {
kvset = nil
datas1 := &types.StoreSet{StateHash: hash1, KV: datas.KV, Height: datas.Height + int64(i)}
s1 := fmt.Sprintf("v1-%03d", datas.Height+int64(i))
s2 := fmt.Sprintf("v2-%03d", datas.Height+int64(i))
datas.KV[0].Value = []byte(s1)
datas.KV[1].Value = []byte(s2)
hash1 = calcHash(datas1)
//zzh
//kmlog.Debug("KVMVCCStore MemSet AddMVCC", "prestatehash", common.ToHex(datas.StateHash), "hash", common.ToHex(hash), "height", datas.Height)
kmlog.Info("KVMVCCStore MemSet AddMVCC for 202", "prestatehash", common.ToHex(datas1.StateHash), "hash", common.ToHex(hash1), "height", datas1.Height)
kvlist, err := store.mvcc.AddMVCC(datas1.KV, hash1, datas1.StateHash, datas1.Height)
if err != nil {
kmlog.Info("KVMVCCStore MemSet AddMVCC failed for 202, continue")
continue
}
if len(kvlist) > 0 {
kvset = append(kvset, kvlist...)
}
store.kvsetmap[string(hash1)] = kvset
req := &types.ReqHash{Hash: hash1}
store.Commit(req)
}
maxVersion, err := store.mvcc.GetMaxVersion()
assert.Equal(t, err, nil)
assert.Equal(t, int64(202), maxVersion)
keys := [][]byte{[]byte("mk1"), []byte("mk2")}
get1 := &types.StoreGet{StateHash: hash, Keys: keys}
values := store.Get(get1)
assert.Len(t, values, 2)
assert.Equal(t, []byte("v1"), values[0])
assert.Equal(t, []byte("v2"), values[1])
var kv2 []*types.KeyValue
kv2 = append(kv2, &types.KeyValue{Key: []byte("mk1"), Value: []byte("v11")})
kv2 = append(kv2, &types.KeyValue{Key: []byte("mk2"), Value: []byte("v22")})
//触发批量回滚
datas2 := &types.StoreSet{StateHash: hash, KV: kv2, Height: 1}
hash, err = store.MemSet(datas2, true)
assert.Nil(t, err)
req = &types.ReqHash{Hash: hash}
store.Commit(req)
maxVersion, err = store.mvcc.GetMaxVersion()
assert.Equal(t, nil, err)
assert.Equal(t, int64(3), maxVersion)
get2 := &types.StoreGet{StateHash: hash, Keys: keys}
values2 := store.Get(get2)
assert.Len(t, values, 2)
assert.Equal(t, values2[0], kv2[0].Value)
assert.Equal(t, values2[1], kv2[1].Value)
datas3 := &types.StoreSet{StateHash: hash, KV: kv2, Height: 2}
hash, err = store.MemSet(datas3, true)
assert.Nil(t, err)
req = &types.ReqHash{Hash: hash}
store.Commit(req)
maxVersion, err = store.mvcc.GetMaxVersion()
assert.Equal(t, nil, err)
assert.Equal(t, int64(2), maxVersion)
}
func enableConfig() []byte {
data, _ := json.Marshal(&subConfig{EnableMVCCIter: true})
return data
}
func TestIterateRangeByStateHash(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVmMavlStore)
assert.NotNil(t, store)
execaddr := "0111vcBNSEA7fZhAdLJphDwQRQJa111"
addr := "06htvcBNSEA7fZhAdLJphDwQRQJaHpy"
addr1 := "16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
addr2 := "26htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
addr3 := "36htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
addr4 := "46htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
accCoin := account.NewCoinsAccount()
account1 := &types.Account{
Balance: 1000 * 1e8,
Addr: addr1,
}
account2 := &types.Account{
Balance: 900 * 1e8,
Addr: addr2,
}
account3 := &types.Account{
Balance: 800 * 1e8,
Addr: addr3,
}
account4 := &types.Account{
Balance: 700 * 1e8,
Addr: addr4,
}
set1 := accCoin.GetKVSet(account1)
set2 := accCoin.GetKVSet(account2)
set3 := accCoin.GetKVSet(account3)
set4 := accCoin.GetKVSet(account4)
set5 := accCoin.GetExecKVSet(execaddr, account4)
fmt.Println("---test case1-1 ---")
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: set4[0].GetKey(), Value: set4[0].GetValue()})
kv = append(kv, &types.KeyValue{Key: set3[0].GetKey(), Value: set3[0].GetValue()})
kv = append(kv, &types.KeyValue{Key: set1[0].GetKey(), Value: set1[0].GetValue()})
kv = append(kv, &types.KeyValue{Key: set2[0].GetKey(), Value: set2[0].GetValue()})
kv = append(kv, &types.KeyValue{Key: set5[0].GetKey(), Value: set5[0].GetValue()})
for i := 0; i < len(kv); i++ {
fmt.Println("key:", string(kv[i].Key), "value:", string(kv[i].Value))
}
datas := &types.StoreSet{StateHash: drivers.EmptyRoot[:], KV: kv, Height: 0}
hash, err := store.MemSet(datas, true)
assert.Nil(t, err)
var kvset []*types.KeyValue
req := &types.ReqHash{Hash: hash}
hash1 := make([]byte, len(hash))
copy(hash1, hash)
store.Commit(req)
resp := &types.ReplyGetTotalCoins{}
resp.Count = 100000
store.IterateRangeByStateHash(hash, []byte("mavl-coins-bty-"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(4), resp.Num)
assert.Equal(t, int64(340000000000), resp.Amount)
// 设置分叉高度
kvmvccMavlFork = 5
defer func() {
kvmvccMavlFork = 200 * 10000
}()
fmt.Println("---test case1-2 ---")
firstForkHash := drivers.EmptyRoot[:]
for i := 1; i <= 10; i++ {
kvset = nil
s1 := fmt.Sprintf("%03d", 11-i)
addrx := addr + s1
account := &types.Account{
Balance: ((1000 + int64(i)) * 1e8),
Addr: addrx,
}
set := accCoin.GetKVSet(account)
fmt.Println("key:", string(set[0].GetKey()), "value:", set[0].GetValue())
kvset = append(kvset, &types.KeyValue{Key: set[0].GetKey(), Value: set[0].GetValue()})
datas1 := &types.StoreSet{StateHash: hash1, KV: kvset, Height: datas.Height + int64(i)}
hash1, err = store.MemSet(datas1, true)
assert.Nil(t, err)
req := &types.ReqHash{Hash: hash1}
store.Commit(req)
if int(kvmvccMavlFork) == i {
firstForkHash = hash1
}
}
resp = &types.ReplyGetTotalCoins{}
resp.Count = 100000
store.IterateRangeByStateHash(hash1, []byte("mavl-coins-bty-"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(14), resp.Num)
assert.Equal(t, int64(1345500000000), resp.Amount)
fmt.Println("---test case1-3 ---")
resp = &types.ReplyGetTotalCoins{}
resp.Count = 100000
store.IterateRangeByStateHash(hash1, []byte("mavl-coins-bty-06htvcBNSEA7fZhAdLJphDwQRQJaHpy003"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(12), resp.Num)
assert.Equal(t, int64(1143600000000), resp.Amount)
fmt.Println("---test case1-4 ---")
resp = &types.ReplyGetTotalCoins{}
resp.Count = 2
store.IterateRangeByStateHash(hash1, []byte("mavl-coins-bty-06htvcBNSEA7fZhAdLJphDwQRQJaHpy003"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(2), resp.Num)
assert.Equal(t, int64(201500000000), resp.Amount)
fmt.Println("---test case1-5 ---")
resp = &types.ReplyGetTotalCoins{}
resp.Count = 2
store.IterateRangeByStateHash(hash1, []byte("mavl-coins-bty-"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(2), resp.Num)
assert.Equal(t, int64(201900000000), resp.Amount)
fmt.Println("---test case1-6 ---")
resp = &types.ReplyGetTotalCoins{}
resp.Count = 10000
store.IterateRangeByStateHash(firstForkHash, []byte("mavl-coins-bty-"), []byte("mavl-coins-bty-exec"), true, resp.IterateRangeByStateHash)
fmt.Println("resp.Num=", resp.Num)
fmt.Println("resp.Amount=", resp.Amount)
assert.Equal(t, int64(0), resp.Num)
assert.Equal(t, int64(0), resp.Amount)
}
func GetRandomString(length int) string {
return common.GetRandPrintString(20, length)
}
func TestDelMavlData(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg := newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(t, store)
db := store.GetDB()
db.Set([]byte(mvccPrefix), []byte("value1"))
db.Set([]byte(fmt.Sprintf("%s123", mvccPrefix)), []byte("value2"))
db.Set([]byte(fmt.Sprintf("%s546", mvccPrefix)), []byte("value3"))
db.Set([]byte(fmt.Sprintf("123%s", mvccPrefix)), []byte("value4"))
db.Set([]byte("key11"), []byte("value11"))
db.Set([]byte("key22"), []byte("value22"))
quit = false
delMavlData(db)
v, err := db.Get([]byte(mvccPrefix))
require.NoError(t, err)
require.Equal(t, []byte("value1"), v)
v, err = db.Get([]byte(fmt.Sprintf("%s123", mvccPrefix)))
require.NoError(t, err)
require.Equal(t, []byte("value2"), v)
v, err = db.Get([]byte(fmt.Sprintf("%s546", mvccPrefix)))
require.NoError(t, err)
require.Equal(t, []byte("value3"), v)
_, err = db.Get([]byte(fmt.Sprintf("123%s", mvccPrefix)))
require.Error(t, err)
_, err = db.Get([]byte("key11"))
require.Error(t, err)
_, err = db.Get([]byte("key22"))
require.Error(t, err)
_, err = db.Get(genDelMavlKey(mvccPrefix))
require.NoError(t, err)
}
func TestPruning(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg := newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(t, store)
kvmvccStore := NewKVMVCC(&subKVMVCCConfig{}, store.GetDB())
SetPruneHeight(10)
defer SetPruneHeight(0)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
var hashes [][]byte
for i := 0; i < 100; i++ {
datas.Height = int64(i)
value = fmt.Sprintf("vv%d", i)
for j := 0; j < 30; j++ {
datas.KV[j].Value = []byte(value)
}
hash, err := kvmvccStore.MemSet(datas, nil, true)
require.NoError(t, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = kvmvccStore.Commit(req)
require.NoError(t, err)
datas.StateHash = hash
hashes = append(hashes, hash)
}
pruningMVCC(store.GetDB(), 99)
//check
getDatas := &types.StoreGet{
StateHash: drivers.EmptyRoot[:],
Keys: keys,
}
for i := 0; i < len(hashes); i++ {
getDatas.StateHash = hashes[i]
values := store.Get(getDatas)
value = fmt.Sprintf("vv%d", i)
if i < 80 {
for _, v := range values {
require.Equal(t, []byte(nil), v)
}
}
if i > 90 {
for _, v := range values {
require.Equal(t, []byte(value), v)
}
}
}
}
func TestGetKeyVersion(t *testing.T) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(t, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg := newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(t, store)
mvcc := dbm.NewMVCC(store.GetDB())
kvs := []*types.KeyValue{
{Key: []byte("5"), Value: []byte("11")},
{Key: []byte("123"), Value: []byte("111")},
{Key: []byte(""), Value: []byte("1111")},
}
hash := []byte("12345678901234567890123456789012")
vsnkv, err := mvcc.AddMVCC(kvs, hash, nil, 0)
require.NoError(t, err)
for _, kv := range vsnkv {
if bytes.Contains(kv.Key, mvccData) && bytes.Contains(kv.Key, kvs[0].Key) {
k, h, err := getKeyVersion(kv.Key)
require.NoError(t, err)
require.Equal(t, k, kvs[0].Key)
require.Equal(t, h, int64(0))
continue
}
if bytes.Contains(kv.Key, mvccData) && bytes.Contains(kv.Key, kvs[1].Key) {
k, h, err := getKeyVersion(kv.Key)
require.NoError(t, err)
require.Equal(t, k, kvs[1].Key)
require.Equal(t, h, int64(0))
continue
}
if bytes.Contains(kv.Key, mvccData) {
k, h, err := getKeyVersion(kv.Key)
require.NoError(t, err)
require.Equal(t, k, kvs[2].Key)
require.Equal(t, h, int64(0))
}
}
}
func BenchmarkGetkmvccMavl(b *testing.B) { benchmarkGet(b, false) }
func BenchmarkGetkmvcc(b *testing.B) { benchmarkGet(b, true) }
func benchmarkGet(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(b, store)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
//kv = nil
}
assert.Nil(b, err)
start := time.Now()
b.ResetTimer()
for _, key := range keys {
getData := &types.StoreGet{
StateHash: hash,
Keys: [][]byte{key}}
store.Get(getData)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkGet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkStoreGetKvs4NkmvccMavl(b *testing.B) { benchmarkStoreGetKvs4N(b, false) }
func BenchmarkStoreGetKvs4Nkmvcc(b *testing.B) { benchmarkStoreGetKvs4N(b, true) }
func benchmarkStoreGetKvs4N(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(b, store)
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
kvnum := 30
for i := 0; i < kvnum; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
hash, err := store.Set(datas, true)
assert.Nil(b, err)
getData := &types.StoreGet{
StateHash: hash,
Keys: keys}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
values := store.Get(getData)
assert.Len(b, values, kvnum)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreGetKvs4N cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
func BenchmarkStoreGetKvsForNNkmvccMavl(b *testing.B) { benchmarkStoreGetKvsForNN(b, false) }
func BenchmarkStoreGetKvsForNNkmvcc(b *testing.B) { benchmarkStoreGetKvsForNN(b, true) }
func benchmarkStoreGetKvsForNN(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(b, store)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
var hashes [][]byte
for i := 0; i < b.N; i++ {
datas.Height = int64(i)
value = fmt.Sprintf("vv%d", i)
for j := 0; j < 30; j++ {
datas.KV[j].Value = []byte(value)
}
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
datas.StateHash = hash
hashes = append(hashes, hash)
}
start := time.Now()
b.ResetTimer()
getData := &types.StoreGet{
StateHash: hashes[0],
Keys: keys}
for i := 0; i < b.N; i++ {
getData.StateHash = hashes[i]
store.Get(getData)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreGetKvsForNN cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
func BenchmarkStoreGetKvsFor10000kmvccMavl(b *testing.B) { benchmarkStoreGetKvsFor10000(b, false) }
func BenchmarkStoreGetKvsFor10000kmvcc(b *testing.B) { benchmarkStoreGetKvsFor10000(b, true) }
func benchmarkStoreGetKvsFor10000(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(b, store)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
var hashes [][]byte
blocks := 10000
times := 10000
start1 := time.Now()
for i := 0; i < blocks; i++ {
datas.Height = int64(i)
value = fmt.Sprintf("vv%d", i)
for j := 0; j < 30; j++ {
datas.KV[j].Value = []byte(value)
}
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
datas.StateHash = hash
hashes = append(hashes, hash)
}
end1 := time.Now()
start := time.Now()
b.ResetTimer()
getData := &types.StoreGet{
StateHash: hashes[0],
Keys: keys}
for i := 0; i < times; i++ {
getData.StateHash = hashes[i]
store.Get(getData)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreGetKvsFor10000 MemSet&Commit cost time is ", end1.Sub(start1), "blocks is", blocks)
fmt.Println("kvmvcc BenchmarkStoreGetKvsFor10000 Get cost time is", end.Sub(start), "num is ", times, ",blocks is ", blocks)
b.StopTimer()
}
func BenchmarkGetIterkmvccMavl(b *testing.B) { benchmarkGetIter(b, false) }
func BenchmarkGetIterkmvcc(b *testing.B) { benchmarkGetIter(b, true) }
func benchmarkGetIter(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVmMavlStore)
assert.NotNil(b, store)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
//kv = nil
}
assert.Nil(b, err)
start := time.Now()
b.ResetTimer()
for _, key := range keys {
getData := &types.StoreGet{
StateHash: hash,
Keys: [][]byte{key}}
store.Get(getData)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkGet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkSetkmvccMavl(b *testing.B) { benchmarkSet(b, false) }
func BenchmarkSetkmvcc(b *testing.B) { benchmarkSet(b, true) }
func benchmarkSet(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(b, store)
b.Log(dir)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
start := time.Now()
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
_, err = store.Set(datas, true)
assert.Nil(b, err)
//kv = nil
}
end := time.Now()
fmt.Println("mpt BenchmarkSet cost time is", end.Sub(start), "num is", b.N)
}
//上一个用例,一次性插入多对kv;本用例每次插入30对kv,分多次插入,测试性能表现。
func BenchmarkStoreSetkmvccMavl(b *testing.B) { benchmarkStoreSet(b, false) }
func BenchmarkStoreSetkmvcc(b *testing.B) { benchmarkStoreSet(b, true) }
func benchmarkStoreSet(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(b, store)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
hash, err := store.Set(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkSet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkSetIterkmvccMavl(b *testing.B) { benchmarkSetIter(b, false) }
func BenchmarkSetIterkmvcc(b *testing.B) { benchmarkSetIter(b, true) }
func benchmarkSetIter(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVmMavlStore)
assert.NotNil(b, store)
b.Log(dir)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var keys [][]byte
var hash = drivers.EmptyRoot[:]
start := time.Now()
for i := 0; i < b.N; i++ {
key := GetRandomString(MaxKeylenth)
value := fmt.Sprintf("%s%d", key, i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
if i%10000 == 0 {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
hash, err = store.Set(datas, true)
assert.Nil(b, err)
kv = nil
}
}
if kv != nil {
datas := &types.StoreSet{StateHash: hash, KV: kv, Height: 0}
_, err = store.Set(datas, true)
assert.Nil(b, err)
//kv = nil
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkSet cost time is", end.Sub(start), "num is", b.N)
}
//一次设定多对kv,测试一次的时间/多少对kv,来算平均一对kv的耗时。
func BenchmarkMemSetkmvccMavl(b *testing.B) { benchmarkMemSet(b, false) }
func BenchmarkMemSetkmvcc(b *testing.B) { benchmarkMemSet(b, true) }
func benchmarkMemSet(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(b, store)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
end := time.Now()
fmt.Println("kvmvcc BenchmarkMemSet cost time is", end.Sub(start), "num is", b.N)
}
//一次设定30对kv,设定N次,计算每次设定30对kv的耗时。
func BenchmarkStoreMemSetkmvccMavl(b *testing.B) { benchmarkStoreMemSet(b, false) }
func BenchmarkStoreMemSetkmvcc(b *testing.B) { benchmarkStoreMemSet(b, true) }
func benchmarkStoreMemSet(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(b, store)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
req := &types.ReqHash{
Hash: hash}
store.Rollback(req)
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreMemSet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkCommitkmvccMavl(b *testing.B) { benchmarkCommit(b, false) }
func BenchmarkCommitkmvcc(b *testing.B) { benchmarkCommit(b, true) }
func benchmarkCommit(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(b, store)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
end := time.Now()
fmt.Println("kvmvcc BenchmarkCommit cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
func BenchmarkStoreCommitkmvccMavl(b *testing.B) { benchmarkStoreCommit(b, false) }
func BenchmarkStoreCommitkmvcc(b *testing.B) { benchmarkStoreCommit(b, true) }
func benchmarkStoreCommit(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
var storeCfg = newStoreCfg(dir)
store := New(storeCfg, nil).(*KVmMavlStore)
assert.NotNil(b, store)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < 30; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
for i := 0; i < b.N; i++ {
datas.Height = int64(i)
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
datas.StateHash = hash
}
end := time.Now()
fmt.Println("kvmvcc BenchmarkStoreCommit cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
func BenchmarkIterMemSetkmvccMavl(b *testing.B) { benchmarkIterMemSet(b, false) }
func BenchmarkIterMemSetkmvcc(b *testing.B) { benchmarkIterMemSet(b, true) }
//一次设定多对kv,测试一次的时间/多少对kv,来算平均一对kv的耗时。
func benchmarkIterMemSet(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVmMavlStore)
assert.NotNil(b, store)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
assert.NotNil(b, hash)
end := time.Now()
fmt.Println("kvmvcc BenchmarkMemSet cost time is", end.Sub(start), "num is", b.N)
}
func BenchmarkIterCommitkmvccMavl(b *testing.B) { benchmarkIterCommit(b, false) }
func BenchmarkIterCommitkmvcc(b *testing.B) { benchmarkIterCommit(b, true) }
func benchmarkIterCommit(b *testing.B, isResetForkHeight bool) {
dir, err := ioutil.TempDir("", "example")
assert.Nil(b, err)
defer os.RemoveAll(dir) // clean up
os.RemoveAll(dir) //删除已存在目录
storeCfg, sub := newStoreCfgIter(dir)
store := New(storeCfg, sub).(*KVmMavlStore)
assert.NotNil(b, store)
if isResetForkHeight {
kvmvccMavlFork = 0
defer func() {
kvmvccMavlFork = 200 * 10000
}()
}
var kv []*types.KeyValue
var key string
var value string
var keys [][]byte
for i := 0; i < b.N; i++ {
key = GetRandomString(MaxKeylenth)
value = fmt.Sprintf("v%d", i)
keys = append(keys, []byte(string(key)))
kv = append(kv, &types.KeyValue{Key: []byte(string(key)), Value: []byte(string(value))})
}
datas := &types.StoreSet{
StateHash: drivers.EmptyRoot[:],
KV: kv,
Height: 0}
start := time.Now()
b.ResetTimer()
hash, err := store.MemSet(datas, true)
assert.Nil(b, err)
req := &types.ReqHash{
Hash: hash,
}
_, err = store.Commit(req)
assert.NoError(b, err, "NoError")
end := time.Now()
fmt.Println("kvmvcc BenchmarkCommit cost time is", end.Sub(start), "num is", b.N)
b.StopTimer()
}
// 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 kvmvccmavl
import (
"bytes"
"fmt"
"strconv"
"sync/atomic"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/queue"
"github.com/33cn/chain33/types"
"github.com/golang/protobuf/proto"
)
const (
pruningStateStart = 1
pruningStateEnd = 0
onceScanCount = 10000 // 单次扫描数目
onceCount = 1000 // 容器长度
levelPruningHeight = 100 * 10000
)
var (
maxRollbackNum = 200
// 是否开启裁剪
enablePrune bool
// 每个10000裁剪一次
pruneHeight = 10000
pruningState int32
)
var (
//同common/db中的mvcc相关的定义保持一致
mvccPrefix = []byte(".-mvcc-.")
//mvccMeta = append(mvccPrefix, []byte("m.")...)
mvccData = append(mvccPrefix, []byte("d.")...)
//mvccLast = append(mvccPrefix, []byte("l.")...)
//mvccMetaVersion = append(mvccMeta, []byte("version.")...)
//mvccMetaVersionKeyList = append(mvccMeta, []byte("versionkl.")...)
)
// KVMVCCStore provide kvmvcc store interface implementation
type KVMVCCStore struct {
db dbm.DB
mvcc dbm.MVCC
kvsetmap map[string][]*types.KeyValue
enableMVCCIter bool
enableMavlPrune bool
pruneHeight int32
}
// NewKVMVCC construct KVMVCCStore module
func NewKVMVCC(sub *subKVMVCCConfig, db dbm.DB) *KVMVCCStore {
var kvs *KVMVCCStore
enable := false
if sub != nil {
enable = sub.EnableMVCCIter
}
if enable {
kvs = &KVMVCCStore{db, dbm.NewMVCCIter(db), make(map[string][]*types.KeyValue),
true, sub.EnableMavlPrune, sub.PruneHeight}
} else {
kvs = &KVMVCCStore{db, dbm.NewMVCC(db), make(map[string][]*types.KeyValue),
false, sub.EnableMavlPrune, sub.PruneHeight}
}
EnablePrune(sub.EnableMavlPrune)
SetPruneHeight(int(sub.PruneHeight))
return kvs
}
// Close the KVMVCCStore module
func (mvccs *KVMVCCStore) Close() {
kmlog.Info("store kvdb closed")
}
// Set kvs with statehash to KVMVCCStore
func (mvccs *KVMVCCStore) Set(datas *types.StoreSet, hash []byte, sync bool) ([]byte, error) {
if hash == nil {
hash = calcHash(datas)
}
kvlist, err := mvccs.mvcc.AddMVCC(datas.KV, hash, datas.StateHash, datas.Height)
if err != nil {
return nil, err
}
mvccs.saveKVSets(kvlist)
return hash, nil
}
// Get kvs with statehash from KVMVCCStore
func (mvccs *KVMVCCStore) Get(datas *types.StoreGet) [][]byte {
values := make([][]byte, len(datas.Keys))
version, err := mvccs.mvcc.GetVersion(datas.StateHash)
if err != nil {
kmlog.Error("Get version by hash failed.", "hash", common.ToHex(datas.StateHash))
return values
}
for i := 0; i < len(datas.Keys); i++ {
value, err := mvccs.mvcc.GetV(datas.Keys[i], version)
if err != nil {
//kmlog.Error("GetV by Keys failed.", "Key", string(datas.Keys[i]), "version", version)
} else if value != nil {
values[i] = value
}
}
return values
}
// MemSet set kvs to the mem of KVMVCCStore module and return the StateHash
func (mvccs *KVMVCCStore) MemSet(datas *types.StoreSet, hash []byte, sync bool) ([]byte, error) {
kvset, err := mvccs.checkVersion(datas.Height)
if err != nil {
return nil, err
}
if hash == nil {
hash = calcHash(datas)
}
//kmlog.Debug("KVMVCCStore MemSet AddMVCC", "prestatehash", common.ToHex(datas.StateHash), "hash", common.ToHex(hash), "height", datas.Height)
kvlist, err := mvccs.mvcc.AddMVCC(datas.KV, hash, datas.StateHash, datas.Height)
if err != nil {
return nil, err
}
if len(kvlist) > 0 {
kvset = append(kvset, kvlist...)
}
mvccs.kvsetmap[string(hash)] = kvset
// 进行裁剪
if enablePrune && !isPruning() &&
pruneHeight != 0 &&
datas.Height%int64(pruneHeight) == 0 &&
datas.Height/int64(pruneHeight) > 1 {
wg.Add(1)
go pruning(mvccs.db, datas.Height)
}
return hash, nil
}
// Commit kvs in the mem of KVMVCCStore module to state db and return the StateHash
func (mvccs *KVMVCCStore) Commit(req *types.ReqHash) ([]byte, error) {
_, ok := mvccs.kvsetmap[string(req.Hash)]
if !ok {
kmlog.Error("store kvmvcc commit", "err", types.ErrHashNotFound)
return nil, types.ErrHashNotFound
}
//kmlog.Debug("KVMVCCStore Commit saveKVSets", "hash", common.ToHex(req.Hash))
mvccs.saveKVSets(mvccs.kvsetmap[string(req.Hash)])
delete(mvccs.kvsetmap, string(req.Hash))
return req.Hash, nil
}
// Rollback kvs in the mem of KVMVCCStore module and return the StateHash
func (mvccs *KVMVCCStore) Rollback(req *types.ReqHash) ([]byte, error) {
_, ok := mvccs.kvsetmap[string(req.Hash)]
if !ok {
kmlog.Error("store kvmvcc rollback", "err", types.ErrHashNotFound)
return nil, types.ErrHashNotFound
}
//kmlog.Debug("KVMVCCStore Rollback", "hash", common.ToHex(req.Hash))
delete(mvccs.kvsetmap, string(req.Hash))
return req.Hash, nil
}
// IterateRangeByStateHash travel with Prefix by StateHash to get the latest version kvs.
func (mvccs *KVMVCCStore) IterateRangeByStateHash(statehash []byte, start []byte, end []byte, ascending bool, fn func(key, value []byte) bool) {
if !mvccs.enableMVCCIter {
panic("call IterateRangeByStateHash when disable mvcc iter")
}
//按照kv最新值来进行遍历处理,要求statehash必须是最新区块的statehash,否则不支持该接口
maxVersion, err := mvccs.mvcc.GetMaxVersion()
if err != nil {
kmlog.Error("KVMVCCStore IterateRangeByStateHash can't get max version, ignore the call.", "err", err)
return
}
version, err := mvccs.mvcc.GetVersion(statehash)
if err != nil {
kmlog.Error("KVMVCCStore IterateRangeByStateHash can't get version, ignore the call.", "stateHash", common.ToHex(statehash), "err", err)
return
}
if version != maxVersion {
kmlog.Error("KVMVCCStore IterateRangeByStateHash call failed for maxVersion does not match version.", "maxVersion", maxVersion, "version", version, "stateHash", common.ToHex(statehash))
return
}
//kmlog.Info("KVMVCCStore do the IterateRangeByStateHash")
listhelper := dbm.NewListHelper(mvccs.mvcc.(*dbm.MVCCIter))
listhelper.IteratorCallback(start, end, 0, 1, fn)
}
// ProcEvent handles supported events
func (mvccs *KVMVCCStore) ProcEvent(msg queue.Message) {
msg.ReplyErr("KVStore", types.ErrActionNotSupport)
}
// Del set kvs to nil with StateHash
func (mvccs *KVMVCCStore) Del(req *types.StoreDel) ([]byte, error) {
kvset, err := mvccs.mvcc.DelMVCC(req.StateHash, req.Height, true)
if err != nil {
kmlog.Error("store kvmvcc del", "err", err)
return nil, err
}
kmlog.Info("KVMVCCStore Del", "hash", common.ToHex(req.StateHash), "height", req.Height)
mvccs.saveKVSets(kvset)
return req.StateHash, nil
}
func (mvccs *KVMVCCStore) saveKVSets(kvset []*types.KeyValue) {
if len(kvset) == 0 {
return
}
storeBatch := mvccs.db.NewBatch(true)
for i := 0; i < len(kvset); i++ {
if kvset[i].Value == nil {
storeBatch.Delete(kvset[i].Key)
} else {
storeBatch.Set(kvset[i].Key, kvset[i].Value)
}
}
storeBatch.Write()
}
func (mvccs *KVMVCCStore) checkVersion(height int64) ([]*types.KeyValue, error) {
//检查新加入区块的height和现有的version的关系,来判断是否要回滚数据
maxVersion, err := mvccs.mvcc.GetMaxVersion()
if err != nil {
if err != types.ErrNotFound {
kmlog.Error("store kvmvcc checkVersion GetMaxVersion failed", "err", err)
panic(err)
} else {
maxVersion = -1
}
}
//kmlog.Debug("store kvmvcc checkVersion ", "maxVersion", maxVersion, "currentVersion", height)
var kvset []*types.KeyValue
if maxVersion < height-1 {
kmlog.Error("store kvmvcc checkVersion found statehash lost", "maxVersion", maxVersion, "height", height)
return nil, ErrStateHashLost
} else if maxVersion == height-1 {
return nil, nil
} else {
count := 1
for i := maxVersion; i >= height; i-- {
hash, err := mvccs.mvcc.GetVersionHash(i)
if err != nil {
kmlog.Warn("store kvmvcc checkVersion GetVersionHash failed", "height", i, "maxVersion", maxVersion)
continue
}
kvlist, err := mvccs.mvcc.DelMVCC(hash, i, false)
if err != nil {
kmlog.Warn("store kvmvcc checkVersion DelMVCC failed", "height", i, "err", err)
continue
}
kvset = append(kvset, kvlist...)
kmlog.Debug("store kvmvcc checkVersion DelMVCC4Height", "height", i, "maxVersion", maxVersion)
//为避免高度差过大时出现异常,做一个保护,一次最多回滚200个区块
count++
if count >= maxRollbackNum {
break
}
}
}
return kvset, nil
}
func calcHash(datas proto.Message) []byte {
b := types.Encode(datas)
return common.Sha256(b)
}
/*裁剪-------------------------------------------*/
// EnablePrune 使能裁剪
func EnablePrune(enable bool) {
enablePrune = enable
}
// SetPruneHeight 设置每次裁剪高度
func SetPruneHeight(height int) {
pruneHeight = height
}
func pruning(db dbm.DB, height int64) {
defer wg.Done()
pruningMVCC(db, height)
}
func pruningMVCC(db dbm.DB, height int64) {
setPruning(pruningStateStart)
defer setPruning(pruningStateEnd)
pruningFirst(db, height)
}
func pruningFirst(db dbm.DB, curHeight int64) {
it := db.Iterator(mvccData, nil, true)
defer it.Close()
var mp map[string][]int64
count := 0
batch := db.NewBatch(true)
for it.Rewind(); it.Valid(); it.Next() {
if quit {
//该处退出
return
}
if mp == nil {
mp = make(map[string][]int64, onceCount)
}
key, height, err := getKeyVersion(it.Key())
if err != nil {
continue
}
if curHeight < height+levelPruningHeight &&
curHeight >= height+int64(pruneHeight) {
mp[string(key)] = append(mp[string(key)], height)
count++
}
if len(mp) >= onceCount-1 || count > onceScanCount {
deleteOldKV(mp, curHeight, batch)
mp = nil
count = 0
}
}
if len(mp) > 0 {
deleteOldKV(mp, curHeight, batch)
mp = nil
_ = mp
}
}
func deleteOldKV(mp map[string][]int64, curHeight int64, batch dbm.Batch) {
if len(mp) == 0 {
return
}
batch.Reset()
for key, vals := range mp {
if len(vals) > 1 && vals[1] != vals[0] { //防止相同高度时候出现的误删除
for _, val := range vals[1:] { //从第二个开始判断
if curHeight >= val+int64(pruneHeight) {
batch.Delete(genKeyVersion([]byte(key), val)) // 删除老版本key
if batch.ValueSize() > batchDataSize {
batch.Write()
batch.Reset()
}
}
}
}
delete(mp, key)
}
batch.Write()
}
func genKeyVersion(key []byte, height int64) []byte {
b := append([]byte{}, mvccData...)
newkey := append(b, key...)
newkey = append(newkey, []byte(".")...)
newkey = append(newkey, pad(height)...)
return newkey
}
func getKeyVersion(vsnKey []byte) ([]byte, int64, error) {
if !bytes.Contains(vsnKey, mvccData) {
return nil, 0, types.ErrSize
}
if len(vsnKey) < len(mvccData)+1+20 {
return nil, 0, types.ErrSize
}
sLen := vsnKey[len(vsnKey)-20:]
iLen, err := strconv.Atoi(string(sLen))
if err != nil {
return nil, 0, types.ErrSize
}
k := bytes.TrimPrefix(vsnKey, mvccData)
key := k[:len(k)-1-20]
return key, int64(iLen), nil
}
func pad(version int64) []byte {
s := fmt.Sprintf("%020d", version)
return []byte(s)
}
func isPruning() bool {
return atomic.LoadInt32(&pruningState) == 1
}
func setPruning(state int32) {
atomic.StoreInt32(&pruningState, state)
}
// 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 kvmvccmavl
import (
"sync"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/queue"
"github.com/33cn/chain33/system/store/mavl/db"
"github.com/33cn/chain33/types"
)
// MavlStore mavl store struct
type MavlStore struct {
db dbm.DB
trees *sync.Map
enableMavlPrefix bool
enableMVCC bool
enableMavlPrune bool
pruneHeight int32
}
// NewMavl new mavl store module
func NewMavl(sub *subMavlConfig, db dbm.DB) *MavlStore {
var subcfg subMavlConfig
if sub != nil {
subcfg.EnableMavlPrefix = sub.EnableMavlPrefix
subcfg.EnableMVCC = sub.EnableMVCC
subcfg.EnableMavlPrune = sub.EnableMavlPrune
subcfg.PruneHeight = sub.PruneHeight
}
mavls := &MavlStore{db, &sync.Map{}, subcfg.EnableMavlPrefix, subcfg.EnableMVCC, subcfg.EnableMavlPrune, subcfg.PruneHeight}
mavl.EnableMavlPrefix(subcfg.EnableMavlPrefix)
mavl.EnableMVCC(subcfg.EnableMVCC)
mavl.EnablePrune(subcfg.EnableMavlPrune)
mavl.SetPruneHeight(int(subcfg.PruneHeight))
return mavls
}
// Close close mavl store
func (mavls *MavlStore) Close() {
mavl.ClosePrune()
kmlog.Info("store mavl closed")
}
// Set set k v to mavl store db; sync is true represent write sync
func (mavls *MavlStore) Set(datas *types.StoreSet, sync bool) ([]byte, error) {
return mavl.SetKVPair(mavls.db, datas, sync)
}
// Get get values by keys
func (mavls *MavlStore) Get(datas *types.StoreGet) [][]byte {
var tree *mavl.Tree
var err error
values := make([][]byte, len(datas.Keys))
search := string(datas.StateHash)
if data, ok := mavls.trees.Load(search); ok {
tree = data.(*mavl.Tree)
} else {
tree = mavl.NewTree(mavls.db, true)
//get接口也应该传入高度
//tree.SetBlockHeight(datas.Height)
err = tree.Load(datas.StateHash)
kmlog.Debug("store mavl get tree", "err", err, "StateHash", common.ToHex(datas.StateHash))
}
if err == nil {
for i := 0; i < len(datas.Keys); i++ {
_, value, exit := tree.Get(datas.Keys[i])
if exit {
values[i] = value
}
}
}
return values
}
// MemSet set keys values to memcory mavl, return root hash and error
func (mavls *MavlStore) MemSet(datas *types.StoreSet, sync bool) ([]byte, error) {
beg := types.Now()
defer func() {
kmlog.Info("MemSet", "cost", types.Since(beg))
}()
if len(datas.KV) == 0 {
kmlog.Info("store mavl memset,use preStateHash as stateHash for kvset is null")
mavls.trees.Store(string(datas.StateHash), nil)
return datas.StateHash, nil
}
tree := mavl.NewTree(mavls.db, sync)
tree.SetBlockHeight(datas.Height)
err := tree.Load(datas.StateHash)
if err != nil {
return nil, err
}
for i := 0; i < len(datas.KV); i++ {
tree.Set(datas.KV[i].Key, datas.KV[i].Value)
}
hash := tree.Hash()
mavls.trees.Store(string(hash), tree)
return hash, nil
}
// Commit convert memcory mavl to storage db
func (mavls *MavlStore) Commit(req *types.ReqHash) ([]byte, error) {
beg := types.Now()
defer func() {
kmlog.Info("Commit", "cost", types.Since(beg))
}()
tree, ok := mavls.trees.Load(string(req.Hash))
if !ok {
kmlog.Error("store mavl commit", "err", types.ErrHashNotFound)
return nil, types.ErrHashNotFound
}
if tree == nil {
kmlog.Info("store mavl commit,do nothing for kvset is null")
mavls.trees.Delete(string(req.Hash))
return req.Hash, nil
}
hash := tree.(*mavl.Tree).Save()
if hash == nil {
kmlog.Error("store mavl commit", "err", types.ErrHashNotFound)
return nil, types.ErrDataBaseDamage
}
mavls.trees.Delete(string(req.Hash))
return req.Hash, nil
}
// Rollback 回退将缓存的mavl树删除掉
func (mavls *MavlStore) Rollback(req *types.ReqHash) ([]byte, error) {
beg := types.Now()
defer func() {
kmlog.Info("Rollback", "cost", types.Since(beg))
}()
_, ok := mavls.trees.Load(string(req.Hash))
if !ok {
kmlog.Error("store mavl rollback", "err", types.ErrHashNotFound)
return nil, types.ErrHashNotFound
}
mavls.trees.Delete(string(req.Hash))
return req.Hash, nil
}
// IterateRangeByStateHash 迭代实现功能; statehash:当前状态hash, start:开始查找的key, end: 结束的key, ascending:升序,降序, fn 迭代回调函数
func (mavls *MavlStore) IterateRangeByStateHash(statehash []byte, start []byte, end []byte, ascending bool, fn func(key, value []byte) bool) {
mavl.IterateRangeByStateHash(mavls.db, statehash, start, end, ascending, fn)
}
// ProcEvent not support message
func (mavls *MavlStore) ProcEvent(msg queue.Message) {
msg.ReplyErr("Store", types.ErrActionNotSupport)
}
// Del ...
func (mavls *MavlStore) Del(req *types.StoreDel) ([]byte, error) {
//not support
return nil, nil
}
...@@ -11,7 +11,7 @@ matrix: ...@@ -11,7 +11,7 @@ matrix:
- name: check_fmt - name: check_fmt
sudo: require sudo: require
go: go:
- "1.9" - "1.11.x"
- master - master
install: install:
- go get -u golang.org/x/tools/cmd/goimports - go get -u golang.org/x/tools/cmd/goimports
......
...@@ -472,3 +472,40 @@ func (acc *DB) mintReceipt(kv []*types.KeyValue, receipt proto.Message) *types.R ...@@ -472,3 +472,40 @@ func (acc *DB) mintReceipt(kv []*types.KeyValue, receipt proto.Message) *types.R
Logs: []*types.ReceiptLog{log1}, Logs: []*types.ReceiptLog{log1},
} }
} }
// Burn 然收
func (acc *DB) Burn(addr string, amount int64) (*types.Receipt, error) {
if !types.CheckAmount(amount) {
return nil, types.ErrAmount
}
accTo := acc.LoadAccount(addr)
if accTo.Balance < amount {
return nil, types.ErrNoBalance
}
copyAcc := *accTo
accTo.Balance = accTo.Balance - amount
receipt := &types.ReceiptAccountBurn{
Prev: &copyAcc,
Current: accTo,
}
kv := acc.GetKVSet(accTo)
acc.SaveKVSet(kv)
return acc.burnReceipt(kv, receipt), nil
}
func (acc *DB) burnReceipt(kv []*types.KeyValue, receipt proto.Message) *types.Receipt {
ty := int32(types.TyLogBurn)
log1 := &types.ReceiptLog{
Ty: ty,
Log: types.Encode(receipt),
}
return &types.Receipt{
Ty: types.ExecOk,
KV: kv,
Logs: []*types.ReceiptLog{log1},
}
}
...@@ -591,3 +591,13 @@ func TestDB_Mint(t *testing.T) { ...@@ -591,3 +591,13 @@ func TestDB_Mint(t *testing.T) {
t.Logf("Token mint addr balance [%d]", tokenCoin.LoadAccount(addr1).Balance) t.Logf("Token mint addr balance [%d]", tokenCoin.LoadAccount(addr1).Balance)
require.Equal(t, int64(1000*1e8+10*1e8), tokenCoin.LoadAccount(addr1).Balance) require.Equal(t, int64(1000*1e8+10*1e8), tokenCoin.LoadAccount(addr1).Balance)
} }
func TestDB_Burn(t *testing.T) {
_, tokenCoin := GenerAccDb()
tokenCoin.GenerAccData()
_, err := tokenCoin.Burn(addr1, 10*1e8)
require.NoError(t, err)
t.Logf("Token mint addr balance [%d]", tokenCoin.LoadAccount(addr1).Balance)
require.Equal(t, int64(1000*1e8-10*1e8), tokenCoin.LoadAccount(addr1).Balance)
}
...@@ -90,6 +90,10 @@ enableMVCC=false ...@@ -90,6 +90,10 @@ enableMVCC=false
enableMavlPrune=false enableMavlPrune=false
# 裁剪高度间隔 # 裁剪高度间隔
pruneHeight=10000 pruneHeight=10000
# 是否使能mavl数据载入内存
enableMemTree=false
# 是否使能mavl叶子节点数据载入内存
enableMemVal=false
[wallet] [wallet]
# walletdb路径 # walletdb路径
......
...@@ -144,6 +144,10 @@ enableMavlPrefix=false ...@@ -144,6 +144,10 @@ enableMavlPrefix=false
enableMVCC=false enableMVCC=false
enableMavlPrune=false enableMavlPrune=false
pruneHeight=10000 pruneHeight=10000
# 是否使能mavl数据载入内存
enableMemTree=false
# 是否使能mavl叶子节点数据载入内存
enableMemVal=false
[wallet] [wallet]
minFee=1000000 minFee=1000000
......
...@@ -210,6 +210,10 @@ enableMVCC=false ...@@ -210,6 +210,10 @@ enableMVCC=false
enableMavlPrune=false enableMavlPrune=false
# 裁剪高度间隔 # 裁剪高度间隔
pruneHeight=10000 pruneHeight=10000
# 是否使能mavl数据载入内存
enableMemTree=false
# 是否使能mavl叶子节点数据载入内存
enableMemVal=false
[wallet] [wallet]
# 交易发送最低手续费,单位0.00000001BTY(1e-8),默认100000,即0.001BTY # 交易发送最低手续费,单位0.00000001BTY(1e-8),默认100000,即0.001BTY
......
...@@ -203,11 +203,24 @@ func (e *executor) Exec(tx *types.Transaction, index int) (*types.Receipt, error ...@@ -203,11 +203,24 @@ func (e *executor) Exec(tx *types.Transaction, index int) (*types.Receipt, error
if err := drivers.CheckAddress(tx.GetRealToAddr(), e.height); err != nil { if err := drivers.CheckAddress(tx.GetRealToAddr(), e.height); err != nil {
return nil, err return nil, err
} }
if e.localDB != nil {
e.localDB.(*LocalDB).DisableWrite()
if exec.ExecutorOrder() != drivers.ExecLocalSameTime {
e.localDB.(*LocalDB).DisableRead()
}
defer func() {
e.localDB.(*LocalDB).EnableWrite()
if exec.ExecutorOrder() != drivers.ExecLocalSameTime {
e.localDB.(*LocalDB).EnableRead()
}
}()
}
//第一步先检查 CheckTx //第一步先检查 CheckTx
if err := exec.CheckTx(tx, index); err != nil { if err := exec.CheckTx(tx, index); err != nil {
return nil, err return nil, err
} }
return exec.Exec(tx, index) r, err := exec.Exec(tx, index)
return r, err
} }
func (e *executor) execLocal(tx *types.Transaction, r *types.ReceiptData, index int) (*types.LocalDBSet, error) { func (e *executor) execLocal(tx *types.Transaction, r *types.ReceiptData, index int) (*types.LocalDBSet, error) {
......
...@@ -312,7 +312,10 @@ func (demo *demoApp) Exec(tx *types.Transaction, index int) (receipt *types.Rece ...@@ -312,7 +312,10 @@ func (demo *demoApp) Exec(tx *types.Transaction, index int) (receipt *types.Rece
} }
if seterrkey { if seterrkey {
println("set err key value") println("set err key value")
demo.GetLocalDB().Set([]byte("key1"), []byte("value1")) err = demo.GetLocalDB().Set([]byte("key1"), []byte("value1"))
if err != nil {
return nil, err
}
} }
receipt = &types.Receipt{Ty: types.ExecOk} receipt = &types.Receipt{Ty: types.ExecOk}
receipt.KV = append(receipt.KV, &types.KeyValue{ receipt.KV = append(receipt.KV, &types.KeyValue{
...@@ -401,11 +404,14 @@ func TestExecLocalSameTime0(t *testing.T) { ...@@ -401,11 +404,14 @@ func TestExecLocalSameTime0(t *testing.T) {
return return
} }
for i, receipt := range detail.Receipts { for i, receipt := range detail.Receipts {
assert.Equal(t, receipt.GetTy(), int32(2), fmt.Sprint(i)) if i == 0 {
assert.Equal(t, receipt.GetTy(), int32(2), fmt.Sprint(i))
}
if i >= 1 { if i >= 1 {
assert.Equal(t, receipt.GetTy(), int32(1), fmt.Sprint(i))
fmt.Println(receipt) fmt.Println(receipt)
assert.Equal(t, len(receipt.Logs), 2) assert.Equal(t, len(receipt.Logs), 2)
assert.Equal(t, receipt.Logs[1].Ty, int32(0)) assert.Equal(t, receipt.Logs[1].Ty, int32(1))
} }
} }
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package executor package executor
import ( import (
"fmt"
"testing" "testing"
"time" "time"
...@@ -198,5 +199,6 @@ func TestExecutorErrAPIEnv(t *testing.T) { ...@@ -198,5 +199,6 @@ func TestExecutorErrAPIEnv(t *testing.T) {
msg := queue.NewMessage(0, "", 1, txlist) msg := queue.NewMessage(0, "", 1, txlist)
exec.procExecTxList(msg) exec.procExecTxList(msg)
_, err := exec.client.WaitTimeout(msg, 100*time.Second) _, err := exec.client.WaitTimeout(msg, 100*time.Second)
fmt.Println(err)
assert.Equal(t, true, api.IsAPIEnvError(err)) assert.Equal(t, true, api.IsAPIEnvError(err))
} }
...@@ -12,15 +12,17 @@ import ( ...@@ -12,15 +12,17 @@ import (
//数据的get set 主要经过 cache //数据的get set 主要经过 cache
//如果需要进行list, 那么把get set 的内容加入到 后端数据库 //如果需要进行list, 那么把get set 的内容加入到 后端数据库
type LocalDB struct { type LocalDB struct {
cache map[string][]byte cache map[string][]byte
txcache map[string][]byte txcache map[string][]byte
keys []string keys []string
intx bool intx bool
hasbegin bool hasbegin bool
kvs []*types.KeyValue kvs []*types.KeyValue
txid *types.Int64 txid *types.Int64
client queue.Client client queue.Client
api client.QueueProtocolAPI api client.QueueProtocolAPI
disableread bool
disablewrite bool
} }
//NewLocalDB 创建一个新的LocalDB //NewLocalDB 创建一个新的LocalDB
...@@ -41,6 +43,26 @@ func NewLocalDB(cli queue.Client) db.KVDB { ...@@ -41,6 +43,26 @@ func NewLocalDB(cli queue.Client) db.KVDB {
} }
} }
//DisableRead 禁止读取LocalDB数据库
func (l *LocalDB) DisableRead() {
l.disableread = true
}
//DisableWrite 禁止写LocalDB数据库
func (l *LocalDB) DisableWrite() {
l.disablewrite = true
}
//EnableRead 启动读取LocalDB数据库
func (l *LocalDB) EnableRead() {
l.disableread = false
}
//EnableWrite 启动写LocalDB数据库
func (l *LocalDB) EnableWrite() {
l.disablewrite = false
}
func (l *LocalDB) resetTx() { func (l *LocalDB) resetTx() {
l.intx = false l.intx = false
l.txcache = nil l.txcache = nil
...@@ -128,6 +150,9 @@ func (l *LocalDB) Rollback() { ...@@ -128,6 +150,9 @@ func (l *LocalDB) Rollback() {
//Get 获取key //Get 获取key
func (l *LocalDB) Get(key []byte) ([]byte, error) { func (l *LocalDB) Get(key []byte) ([]byte, error) {
if l.disableread {
return nil, types.ErrDisableRead
}
skey := string(key) skey := string(key)
if l.intx && l.txcache != nil { if l.intx && l.txcache != nil {
if value, ok := l.txcache[skey]; ok { if value, ok := l.txcache[skey]; ok {
...@@ -160,6 +185,9 @@ func (l *LocalDB) Get(key []byte) ([]byte, error) { ...@@ -160,6 +185,9 @@ func (l *LocalDB) Get(key []byte) ([]byte, error) {
//Set 获取key //Set 获取key
func (l *LocalDB) Set(key []byte, value []byte) error { func (l *LocalDB) Set(key []byte, value []byte) error {
if l.disablewrite {
return types.ErrDisableWrite
}
skey := string(key) skey := string(key)
if l.intx { if l.intx {
if l.txcache == nil { if l.txcache == nil {
...@@ -176,6 +204,9 @@ func (l *LocalDB) Set(key []byte, value []byte) error { ...@@ -176,6 +204,9 @@ func (l *LocalDB) Set(key []byte, value []byte) error {
// List 从数据库中查询数据列表 // List 从数据库中查询数据列表
func (l *LocalDB) List(prefix, key []byte, count, direction int32) ([][]byte, error) { func (l *LocalDB) List(prefix, key []byte, count, direction int32) ([][]byte, error) {
if l.disableread {
return nil, types.ErrDisableRead
}
err := l.save() err := l.save()
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -18,6 +18,34 @@ func TestLocalDBGet(t *testing.T) { ...@@ -18,6 +18,34 @@ func TestLocalDBGet(t *testing.T) {
testDBGet(t, db) testDBGet(t, db)
} }
func TestLocalDBEnable(t *testing.T) {
mock33 := testnode.New("", nil)
defer mock33.Close()
db := executor.NewLocalDB(mock33.GetClient())
ldb := db.(*executor.LocalDB)
defer ldb.Close()
_, err := ldb.Get([]byte("hello"))
assert.Equal(t, err, types.ErrNotFound)
ldb.DisableRead()
_, err = ldb.Get([]byte("hello"))
assert.Equal(t, err, types.ErrDisableRead)
_, err = ldb.List(nil, nil, 0, 0)
assert.Equal(t, err, types.ErrDisableRead)
ldb.EnableRead()
_, err = ldb.Get([]byte("hello"))
assert.Equal(t, err, types.ErrNotFound)
_, err = ldb.List(nil, nil, 0, 0)
assert.Equal(t, err, nil)
ldb.DisableWrite()
err = ldb.Set([]byte("hello"), nil)
assert.Equal(t, err, types.ErrDisableWrite)
ldb.EnableWrite()
err = ldb.Set([]byte("hello"), nil)
assert.Equal(t, err, nil)
}
func BenchmarkLocalDBGet(b *testing.B) { func BenchmarkLocalDBGet(b *testing.B) {
mock33 := testnode.New("", nil) mock33 := testnode.New("", nil)
defer mock33.Close() defer mock33.Close()
......
...@@ -20,7 +20,7 @@ var ( ...@@ -20,7 +20,7 @@ var (
} }
logmap = map[int64]*types.LogInfo{ logmap = map[int64]*types.LogInfo{
// 这里reflect.TypeOf类型必须是proto.Message类型,且是交易的回持结构 // 这里reflect.TypeOf类型必须是proto.Message类型,且是交易的回持结构
TyLogModifyConfig: {reflect.TypeOf(types.ReceiptConfig{}), "LogModifyConfig"}, TyLogModifyConfig: {Ty: reflect.TypeOf(types.ReceiptConfig{}), Name: "LogModifyConfig"},
} }
) )
......
// 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 mavl
import (
"fmt"
"time"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
farm "github.com/dgryski/go-farm"
"github.com/hashicorp/golang-lru"
)
// MemTreeOpera memtree操作接口
type MemTreeOpera interface {
Add(key, value interface{})
Get(key interface{}) (value interface{}, ok bool)
Delete(key interface{})
Contains(key interface{}) bool
Len() int
}
// TreeMap map形式memtree
type TreeMap struct {
mpCache map[interface{}]interface{}
}
// NewTreeMap new mem tree
func NewTreeMap(size int) *TreeMap {
mp := &TreeMap{}
mp.mpCache = make(map[interface{}]interface{}, size)
return mp
}
// Add 添加元素
func (tm *TreeMap) Add(key, value interface{}) {
if _, ok := tm.mpCache[key]; ok {
delete(tm.mpCache, key)
return
}
tm.mpCache[key] = value
}
// Get 获取元素
func (tm *TreeMap) Get(key interface{}) (value interface{}, ok bool) {
if value, ok := tm.mpCache[key]; ok {
return value, ok
}
return nil, false
}
// Delete 删除元素
func (tm *TreeMap) Delete(key interface{}) {
if _, ok := tm.mpCache[key]; ok {
delete(tm.mpCache, key)
}
}
// Contains 查看是否包含元素
func (tm *TreeMap) Contains(key interface{}) bool {
if _, ok := tm.mpCache[key]; ok {
return true
}
return false
}
// Len 元素长度
func (tm *TreeMap) Len() int {
return len(tm.mpCache)
}
// TreeARC lru的mem tree
type TreeARC struct {
arcCache *lru.ARCCache
}
// NewTreeARC new lru mem tree
func NewTreeARC(size int) *TreeARC {
ma := &TreeARC{}
ma.arcCache, _ = lru.NewARC(size)
return ma
}
// Add 添加元素
func (ta *TreeARC) Add(key, value interface{}) {
if ta.arcCache.Contains(key) {
ta.arcCache.Remove(key)
return
}
ta.arcCache.Add(key, value)
}
// Get 获取元素
func (ta *TreeARC) Get(key interface{}) (value interface{}, ok bool) {
return ta.arcCache.Get(key)
}
// Delete 删除元素
func (ta *TreeARC) Delete(key interface{}) {
ta.arcCache.Remove(key)
}
// Contains 查看是否包含元素
func (ta *TreeARC) Contains(key interface{}) bool {
return ta.arcCache.Contains(key)
}
// Len 元素长度
func (ta *TreeARC) Len() int {
return ta.arcCache.Len()
}
// LoadTree2MemDb 从数据库中载入mem tree
func LoadTree2MemDb(db dbm.DB, hash []byte, mp map[uint64]struct{}) {
nDb := newNodeDB(db, true)
node, err := nDb.getLightNode(nil, hash)
if err != nil {
fmt.Println("err", err)
return
}
pri := ""
if len(node.hash) > 32 {
pri = string(node.hash[:16])
}
treelog.Info("hash node", "hash pri", pri, "hash", common.ToHex(node.hash), "height", node.height)
start := time.Now()
leftHash := make([]byte, len(node.leftHash))
copy(leftHash, node.leftHash)
rightHash := make([]byte, len(node.rightHash))
copy(rightHash, node.rightHash)
mp[farm.Hash64(node.hash)] = struct{}{}
node.loadNodeInfo(nDb, mp)
end := time.Now()
treelog.Info("hash node", "cost time", end.Sub(start), "node count", len(mp))
PrintMemStats(1)
}
func (node *Node) loadNodeInfo(db *nodeDB, mp map[uint64]struct{}) {
if node.height == 0 {
//trMem.Add(Hash64(node.hash), &hashNode{leftHash: node.leftHash, rightHash: node.rightHash})
leftHash := make([]byte, len(node.leftHash))
copy(leftHash, node.leftHash)
rightHash := make([]byte, len(node.rightHash))
copy(rightHash, node.rightHash)
mp[farm.Hash64(node.hash)] = struct{}{}
return
}
if node.leftHash != nil {
left, err := db.getLightNode(nil, node.leftHash)
if err != nil {
return
}
//trMem.Add(Hash64(left.hash), &hashNode{leftHash: left.leftHash, rightHash: left.rightHash})
leftHash := make([]byte, len(left.leftHash))
copy(leftHash, left.leftHash)
rightHash := make([]byte, len(left.rightHash))
copy(rightHash, left.rightHash)
mp[farm.Hash64(left.hash)] = struct{}{}
left.loadNodeInfo(db, mp)
}
if node.rightHash != nil {
right, err := db.getLightNode(nil, node.rightHash)
if err != nil {
return
}
//trMem.Add(Hash64(right.hash), &hashNode{leftHash: right.leftHash, rightHash: right.rightHash})
leftHash := make([]byte, len(right.leftHash))
copy(leftHash, right.leftHash)
rightHash := make([]byte, len(right.rightHash))
copy(rightHash, right.rightHash)
mp[farm.Hash64(right.hash)] = struct{}{}
right.loadNodeInfo(db, mp)
}
}
func (ndb *nodeDB) getLightNode(t *Tree, hash []byte) (*Node, error) {
// Doesn't exist, load from db.
var buf []byte
buf, err := ndb.db.Get(hash)
if len(buf) == 0 || err != nil {
return nil, ErrNodeNotExist
}
node, err := MakeNode(buf, t)
if err != nil {
panic(fmt.Sprintf("Error reading IAVLNode. bytes: %X error: %v", buf, err))
}
node.hash = hash
node.key = nil
node.value = nil
return node, nil
}
func copyBytes(b []byte) (copiedBytes []byte) {
if b == nil {
return nil
}
copiedBytes = make([]byte, len(b))
copy(copiedBytes, b)
return copiedBytes
}
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"github.com/33cn/chain33/common" "github.com/33cn/chain33/common"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
farm "github.com/dgryski/go-farm"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
) )
...@@ -499,6 +500,9 @@ func removeOrphan(t *Tree, node *Node) { ...@@ -499,6 +500,9 @@ func removeOrphan(t *Tree, node *Node) {
if t.ndb == nil { if t.ndb == nil {
return return
} }
if enableMemTree && t != nil {
t.obsoleteNode[uintkey(farm.Hash64(node.hash))] = struct{}{}
}
t.ndb.RemoveNode(t, node) t.ndb.RemoveNode(t, node)
} }
......
...@@ -15,6 +15,7 @@ import ( ...@@ -15,6 +15,7 @@ import (
dbm "github.com/33cn/chain33/common/db" dbm "github.com/33cn/chain33/common/db"
log "github.com/33cn/chain33/common/log/log15" log "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
farm "github.com/dgryski/go-farm"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/hashicorp/golang-lru" "github.com/hashicorp/golang-lru"
) )
...@@ -37,6 +38,10 @@ var ( ...@@ -37,6 +38,10 @@ var (
// 当前树的最大高度 // 当前树的最大高度
maxBlockHeight int64 maxBlockHeight int64
heightMtx sync.Mutex heightMtx sync.Mutex
//
enableMemTree bool
memTree MemTreeOpera
enableMemVal bool
) )
// EnableMavlPrefix 使能mavl加前缀 // EnableMavlPrefix 使能mavl加前缀
...@@ -49,23 +54,53 @@ func EnableMVCC(enable bool) { ...@@ -49,23 +54,53 @@ func EnableMVCC(enable bool) {
enableMvcc = enable enableMvcc = enable
} }
// EnableMemTree 使能mavl数据载入内存
func EnableMemTree(enable bool) {
enableMemTree = enable
}
// EnableMemVal 使能mavl叶子节点数据载入内存
func EnableMemVal(enable bool) {
enableMemVal = enable
}
type memNode struct {
data [][]byte //顺序为lefthash, righthash, key, value
Height int32
Size int32
}
type uintkey uint64
// Tree merkle avl tree // Tree merkle avl tree
type Tree struct { type Tree struct {
root *Node root *Node
ndb *nodeDB ndb *nodeDB
blockHeight int64 blockHeight int64
// 树更新之后,废弃的节点(更新缓存中节点先对旧节点进行删除然后再更新)
obsoleteNode map[uintkey]struct{}
updateNode map[uintkey]*memNode
} }
// NewTree 新建一个merkle avl 树 // NewTree 新建一个merkle avl 树
func NewTree(db dbm.DB, sync bool) *Tree { func NewTree(db dbm.DB, sync bool) *Tree {
if db == nil { if db == nil {
// In-memory IAVLTree // In-memory IAVLTree
return &Tree{} return &Tree{
obsoleteNode: make(map[uintkey]struct{}),
updateNode: make(map[uintkey]*memNode),
}
} }
// Persistent IAVLTree // Persistent IAVLTree
ndb := newNodeDB(db, sync) ndb := newNodeDB(db, sync)
// 使能情况下非空创建当前整tree的缓存
if enableMemTree && memTree == nil {
memTree = NewTreeMap(50 * 10000)
}
return &Tree{ return &Tree{
ndb: ndb, ndb: ndb,
obsoleteNode: make(map[uintkey]struct{}),
updateNode: make(map[uintkey]*memNode),
} }
} }
...@@ -116,13 +151,17 @@ func (t *Tree) Has(key []byte) bool { ...@@ -116,13 +151,17 @@ func (t *Tree) Has(key []byte) bool {
func (t *Tree) Set(key []byte, value []byte) (updated bool) { func (t *Tree) Set(key []byte, value []byte) (updated bool) {
//treelog.Info("IAVLTree.Set", "key", key, "value",value) //treelog.Info("IAVLTree.Set", "key", key, "value",value)
if t.root == nil { if t.root == nil {
t.root = NewNode(key, value) t.root = NewNode(copyBytes(key), copyBytes(value))
return false return false
} }
t.root, updated = t.root.set(t, key, value) t.root, updated = t.root.set(t, copyBytes(key), copyBytes(value))
return updated return updated
} }
func (t *Tree) getObsoleteNode() map[uintkey]struct{} {
return t.obsoleteNode
}
// Hash 计算tree 的roothash // Hash 计算tree 的roothash
func (t *Tree) Hash() []byte { func (t *Tree) Hash() []byte {
if t.root == nil { if t.root == nil {
...@@ -148,6 +187,17 @@ func (t *Tree) Save() []byte { ...@@ -148,6 +187,17 @@ func (t *Tree) Save() []byte {
if enablePrune { if enablePrune {
t.root.saveRootHash(t) t.root.saveRootHash(t)
} }
// 更新memTree
if enableMemTree && memTree != nil {
for k := range t.obsoleteNode {
memTree.Delete(k)
}
for k, v := range t.updateNode {
memTree.Add(k, v)
}
treelog.Debug("Tree.Save", "memTree len", memTree.Len(), "tree height", t.blockHeight)
}
beg := types.Now() beg := types.Now()
err := t.ndb.Commit() err := t.ndb.Commit()
treelog.Info("tree.commit", "cost", types.Since(beg)) treelog.Info("tree.commit", "cost", types.Since(beg))
...@@ -395,6 +445,13 @@ func (ndb *nodeDB) GetNode(t *Tree, hash []byte) (*Node, error) { ...@@ -395,6 +445,13 @@ func (ndb *nodeDB) GetNode(t *Tree, hash []byte) (*Node, error) {
return elem.(*Node), nil return elem.(*Node), nil
} }
} }
//从memtree中获取
if enableMemTree {
node, err := getNode4MemTree(hash)
if err == nil {
return node, nil
}
}
// Doesn't exist, load from db. // Doesn't exist, load from db.
var buf []byte var buf []byte
buf, err := ndb.db.Get(hash) buf, err := ndb.db.Get(hash)
...@@ -409,6 +466,10 @@ func (ndb *nodeDB) GetNode(t *Tree, hash []byte) (*Node, error) { ...@@ -409,6 +466,10 @@ func (ndb *nodeDB) GetNode(t *Tree, hash []byte) (*Node, error) {
node.hash = hash node.hash = hash
node.persisted = true node.persisted = true
ndb.cacheNode(node) ndb.cacheNode(node)
// Save node hashInt64 to memTree
if enableMemTree {
updateGlobalMemTree(node)
}
return node, nil return node, nil
} }
...@@ -459,6 +520,85 @@ func (ndb *nodeDB) SaveNode(t *Tree, node *Node) { ...@@ -459,6 +520,85 @@ func (ndb *nodeDB) SaveNode(t *Tree, node *Node) {
ndb.cacheNode(node) ndb.cacheNode(node)
delete(ndb.orphans, string(node.hash)) delete(ndb.orphans, string(node.hash))
//treelog.Debug("SaveNode", "hash", node.hash, "height", node.height, "value", node.value) //treelog.Debug("SaveNode", "hash", node.hash, "height", node.height, "value", node.value)
// Save node hashInt64 to localmem
if enableMemTree {
updateLocalMemTree(t, node)
}
}
func getNode4MemTree(hash []byte) (*Node, error) {
if memTree == nil {
return nil, ErrNodeNotExist
}
elem, ok := memTree.Get(uintkey(farm.Hash64(hash)))
if ok {
sn := elem.(*memNode)
node := &Node{
height: sn.Height,
size: sn.Size,
hash: hash,
persisted: true,
}
node.leftHash = sn.data[0]
node.rightHash = sn.data[1]
node.key = sn.data[2]
if len(sn.data) == 4 {
node.value = sn.data[3]
}
return node, nil
}
return nil, ErrNodeNotExist
}
// Save node hashInt64 to memTree
func updateGlobalMemTree(node *Node) {
if node == nil || memTree == nil {
return
}
if !enableMemVal && node.height == 0 {
return
}
memN := &memNode{
Height: node.height,
Size: node.size,
}
if node.height == 0 {
memN.data = make([][]byte, 4)
memN.data[3] = node.value
} else {
memN.data = make([][]byte, 3)
}
memN.data[0] = node.leftHash
memN.data[1] = node.rightHash
memN.data[2] = node.key
memTree.Add(uintkey(farm.Hash64(node.hash)), memN)
}
// Save node hashInt64 to localmem
func updateLocalMemTree(t *Tree, node *Node) {
if t == nil || node == nil {
return
}
if !enableMemVal && node.height == 0 {
return
}
if t.updateNode != nil {
memN := &memNode{
Height: node.height,
Size: node.size,
}
if node.height == 0 {
memN.data = make([][]byte, 4)
memN.data[3] = node.value
} else {
memN.data = make([][]byte, 3)
}
memN.data[0] = node.leftHash
memN.data[1] = node.rightHash
memN.data[2] = node.key
t.updateNode[uintkey(farm.Hash64(node.hash))] = memN
//treelog.Debug("Tree.SaveNode", "store struct size", unsafe.Sizeof(store), "byte size", len(storenode), "height", node.height)
}
} }
//cache缓存节点 //cache缓存节点
......
...@@ -15,6 +15,8 @@ import ( ...@@ -15,6 +15,8 @@ import (
"sync" "sync"
"testing" "testing"
"unsafe"
. "github.com/33cn/chain33/common" . "github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/db" "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/log" "github.com/33cn/chain33/common/log"
...@@ -1255,6 +1257,89 @@ func TestDelLeafCountKV(t *testing.T) { ...@@ -1255,6 +1257,89 @@ func TestDelLeafCountKV(t *testing.T) {
} }
} }
func TestGetObsoleteNode(t *testing.T) {
dir, err := ioutil.TempDir("", "datastore")
require.NoError(t, err)
t.Log(dir)
defer os.Remove(dir)
EnableMemTree(true)
EnableMemVal(true)
defer EnableMemTree(false)
defer EnableMemVal(false)
db := db.NewDB("mavltree", "leveldb", dir, 100)
tree := NewTree(db, true)
type record struct {
key string
value string
}
records := []record{
{"abc", "abc"},
{"low", "low"},
{"fan", "fan"},
}
for _, r := range records {
updated := tree.Set([]byte(r.key), []byte(r.value))
if updated {
t.Error("should have not been updated")
}
}
hash := tree.Save()
obs := tree.getObsoleteNode()
require.Equal(t, 0, len(obs))
mp := make(map[uint64]struct{})
LoadTree2MemDb(db, hash, mp)
tree1 := NewTree(db, true)
tree1.Load(hash)
records1 := []record{
{"abc", "abc1"},
{"low", "low1"},
{"fan", "fan1"},
}
for _, r := range records1 {
tree1.Set([]byte(r.key), []byte(r.value))
}
hash1 := tree1.Save()
obs = tree1.getObsoleteNode()
mp1 := make(map[uint64]struct{})
LoadTree2MemDb(db, hash1, mp1)
require.Equal(t, len(mp), len(obs)) //做了全部更新,因此旧节点全部删除
for ob := range obs {
_, ok := mp[uint64(ob)]
if !ok {
require.Error(t, fmt.Errorf("should exist"))
}
}
tree2 := NewTree(db, true)
tree2.Load(hash)
records2 := []record{
{"fan", "fan1"},
{"foo", "foo"},
{"foobaz", "foobaz"},
{"good", "good"},
}
for _, r := range records2 {
tree2.Set([]byte(r.key), []byte(r.value))
}
hash2 := tree2.Save()
obs = tree2.getObsoleteNode()
mp2 := make(map[uint64]struct{})
LoadTree2MemDb(db, hash2, mp2)
//require.Equal(t, 0, len(obs))
for ob := range obs {
_, ok := mp[uint64(ob)]
if !ok {
require.Error(t, fmt.Errorf("should exist"))
}
}
}
func TestPruningFirstLevelNode(t *testing.T) { func TestPruningFirstLevelNode(t *testing.T) {
dir, err := ioutil.TempDir("", "datastore") dir, err := ioutil.TempDir("", "datastore")
require.NoError(t, err) require.NoError(t, err)
...@@ -1899,3 +1984,64 @@ func saveBlock(dbm db.DB, height int64, hash []byte, txN int64, mvcc bool) (newH ...@@ -1899,3 +1984,64 @@ func saveBlock(dbm db.DB, height int64, hash []byte, txN int64, mvcc bool) (newH
} }
return newHash, nil return newHash, nil
} }
func TestSize1(t *testing.T) {
type storeNode struct {
Key []byte
Value []byte
LeftHash []byte
RightHash []byte
Height int32
Size int32
}
type storeNode1 struct {
Key [][]byte
Height int32
Size int32
}
a := types.StoreNode{}
b := storeNode{}
var c []byte
d := storeNode1{}
//arcmp := NewTreeMap(350 * 10000)
//if arcmp == nil {
// return
//}
//for i := 0; i < 300*10000; i++ {
// data := &storeNode{
// Key: []byte("12345678901234567890123456789012"),
// Value: []byte("12345678901234567890123456789012"),
// LeftHash: []byte("12345678901234567890123456789012"),
// RightHash: []byte("12345678901234567890123456789012"),
// //Key: copyBytes([]byte("12345678901234567890123456789012")),
// //Value: copyBytes([]byte("12345678901234567890123456789012")),
// //LeftHash: copyBytes([]byte("12345678901234567890123456789012")),
// //RightHash: copyBytes([]byte("12345678901234567890123456789012")),
// Height: 123,
// Size: 123,
// }
// arcmp.Add(int64(i), data)
//}
//for i := 0; i < 100*10000; i++ {
// data := &storeNode1{}
// data.Height = 123
// data.Size = 123
// d.Key = make([][]byte, 4)
// //d.Key[0] = []byte("12345678901234567890123456789012")
// //d.Key[1] = []byte("12345678901234567890123456789012")
// //d.Key[2] = []byte("12345678901234567890123456789012")
// //d.Key[3] = []byte("12345678901234567890123456789012")
//
// d.Key[0] = copyBytes([]byte("12345678901234567890123456789012"))
// d.Key[1] = copyBytes([]byte("12345678901234567890123456789012"))
// d.Key[2] = copyBytes([]byte("12345678901234567890123456789012"))
// d.Key[3] = copyBytes([]byte("12345678901234567890123456789012"))
// arcmp.Add(int64(i), data)
//}
PrintMemStats(1)
fmt.Println(unsafe.Sizeof(a), unsafe.Sizeof(b), unsafe.Sizeof(c), unsafe.Sizeof(d), len(d.Key), cap(d.Key))
}
...@@ -37,6 +37,8 @@ type Store struct { ...@@ -37,6 +37,8 @@ type Store struct {
enableMVCC bool enableMVCC bool
enableMavlPrune bool enableMavlPrune bool
pruneHeight int32 pruneHeight int32
enableMemTree bool
enableMemVal bool
} }
func init() { func init() {
...@@ -51,6 +53,10 @@ type subConfig struct { ...@@ -51,6 +53,10 @@ type subConfig struct {
EnableMavlPrune bool `json:"enableMavlPrune"` EnableMavlPrune bool `json:"enableMavlPrune"`
// 裁剪高度间隔 // 裁剪高度间隔
PruneHeight int32 `json:"pruneHeight"` PruneHeight int32 `json:"pruneHeight"`
// 是否使能内存树
EnableMemTree bool `json:"enableMemTree"`
// 是否使能内存树中叶子节点
EnableMemVal bool `json:"enableMemVal"`
} }
// New new mavl store module // New new mavl store module
...@@ -60,15 +66,20 @@ func New(cfg *types.Store, sub []byte) queue.Module { ...@@ -60,15 +66,20 @@ func New(cfg *types.Store, sub []byte) queue.Module {
if sub != nil { if sub != nil {
types.MustDecode(sub, &subcfg) types.MustDecode(sub, &subcfg)
} }
mavls := &Store{bs, &sync.Map{}, subcfg.EnableMavlPrefix, subcfg.EnableMVCC, subcfg.EnableMavlPrune, subcfg.PruneHeight} mavls := &Store{bs, &sync.Map{}, subcfg.EnableMavlPrefix, subcfg.EnableMVCC,
subcfg.EnableMavlPrune, subcfg.PruneHeight, subcfg.EnableMemTree, subcfg.EnableMemVal}
mavls.enableMavlPrefix = subcfg.EnableMavlPrefix mavls.enableMavlPrefix = subcfg.EnableMavlPrefix
mavls.enableMVCC = subcfg.EnableMVCC mavls.enableMVCC = subcfg.EnableMVCC
mavls.enableMavlPrune = subcfg.EnableMavlPrune mavls.enableMavlPrune = subcfg.EnableMavlPrune
mavls.pruneHeight = subcfg.PruneHeight mavls.pruneHeight = subcfg.PruneHeight
mavls.enableMemTree = subcfg.EnableMemTree
mavls.enableMemVal = subcfg.EnableMemVal
mavl.EnableMavlPrefix(mavls.enableMavlPrefix) mavl.EnableMavlPrefix(mavls.enableMavlPrefix)
mavl.EnableMVCC(mavls.enableMVCC) mavl.EnableMVCC(mavls.enableMVCC)
mavl.EnablePrune(mavls.enableMavlPrune) mavl.EnablePrune(mavls.enableMavlPrune)
mavl.SetPruneHeight(int(mavls.pruneHeight)) mavl.SetPruneHeight(int(mavls.pruneHeight))
mavl.EnableMemTree(mavls.enableMemTree)
mavl.EnableMemVal(mavls.enableMemVal)
bs.SetChild(mavls) bs.SetChild(mavls)
return mavls return mavls
} }
......
...@@ -248,6 +248,53 @@ func (m *ReceiptAccountMint) GetCurrent() *Account { ...@@ -248,6 +248,53 @@ func (m *ReceiptAccountMint) GetCurrent() *Account {
return nil return nil
} }
type ReceiptAccountBurn struct {
Prev *Account `protobuf:"bytes,1,opt,name=prev,proto3" json:"prev,omitempty"`
Current *Account `protobuf:"bytes,2,opt,name=current,proto3" json:"current,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReceiptAccountBurn) Reset() { *m = ReceiptAccountBurn{} }
func (m *ReceiptAccountBurn) String() string { return proto.CompactTextString(m) }
func (*ReceiptAccountBurn) ProtoMessage() {}
func (*ReceiptAccountBurn) Descriptor() ([]byte, []int) {
return fileDescriptor_8e28828dcb8d24f0, []int{4}
}
func (m *ReceiptAccountBurn) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReceiptAccountBurn.Unmarshal(m, b)
}
func (m *ReceiptAccountBurn) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReceiptAccountBurn.Marshal(b, m, deterministic)
}
func (m *ReceiptAccountBurn) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReceiptAccountBurn.Merge(m, src)
}
func (m *ReceiptAccountBurn) XXX_Size() int {
return xxx_messageInfo_ReceiptAccountBurn.Size(m)
}
func (m *ReceiptAccountBurn) XXX_DiscardUnknown() {
xxx_messageInfo_ReceiptAccountBurn.DiscardUnknown(m)
}
var xxx_messageInfo_ReceiptAccountBurn proto.InternalMessageInfo
func (m *ReceiptAccountBurn) GetPrev() *Account {
if m != nil {
return m.Prev
}
return nil
}
func (m *ReceiptAccountBurn) GetCurrent() *Account {
if m != nil {
return m.Current
}
return nil
}
//查询一个地址列表在某个执行器中余额 //查询一个地址列表在某个执行器中余额
type ReqBalance struct { type ReqBalance struct {
//地址列表 //地址列表
...@@ -266,7 +313,7 @@ func (m *ReqBalance) Reset() { *m = ReqBalance{} } ...@@ -266,7 +313,7 @@ func (m *ReqBalance) Reset() { *m = ReqBalance{} }
func (m *ReqBalance) String() string { return proto.CompactTextString(m) } func (m *ReqBalance) String() string { return proto.CompactTextString(m) }
func (*ReqBalance) ProtoMessage() {} func (*ReqBalance) ProtoMessage() {}
func (*ReqBalance) Descriptor() ([]byte, []int) { func (*ReqBalance) Descriptor() ([]byte, []int) {
return fileDescriptor_8e28828dcb8d24f0, []int{4} return fileDescriptor_8e28828dcb8d24f0, []int{5}
} }
func (m *ReqBalance) XXX_Unmarshal(b []byte) error { func (m *ReqBalance) XXX_Unmarshal(b []byte) error {
...@@ -334,7 +381,7 @@ func (m *Accounts) Reset() { *m = Accounts{} } ...@@ -334,7 +381,7 @@ func (m *Accounts) Reset() { *m = Accounts{} }
func (m *Accounts) String() string { return proto.CompactTextString(m) } func (m *Accounts) String() string { return proto.CompactTextString(m) }
func (*Accounts) ProtoMessage() {} func (*Accounts) ProtoMessage() {}
func (*Accounts) Descriptor() ([]byte, []int) { func (*Accounts) Descriptor() ([]byte, []int) {
return fileDescriptor_8e28828dcb8d24f0, []int{5} return fileDescriptor_8e28828dcb8d24f0, []int{6}
} }
func (m *Accounts) XXX_Unmarshal(b []byte) error { func (m *Accounts) XXX_Unmarshal(b []byte) error {
...@@ -374,7 +421,7 @@ func (m *ExecAccount) Reset() { *m = ExecAccount{} } ...@@ -374,7 +421,7 @@ func (m *ExecAccount) Reset() { *m = ExecAccount{} }
func (m *ExecAccount) String() string { return proto.CompactTextString(m) } func (m *ExecAccount) String() string { return proto.CompactTextString(m) }
func (*ExecAccount) ProtoMessage() {} func (*ExecAccount) ProtoMessage() {}
func (*ExecAccount) Descriptor() ([]byte, []int) { func (*ExecAccount) Descriptor() ([]byte, []int) {
return fileDescriptor_8e28828dcb8d24f0, []int{6} return fileDescriptor_8e28828dcb8d24f0, []int{7}
} }
func (m *ExecAccount) XXX_Unmarshal(b []byte) error { func (m *ExecAccount) XXX_Unmarshal(b []byte) error {
...@@ -421,7 +468,7 @@ func (m *AllExecBalance) Reset() { *m = AllExecBalance{} } ...@@ -421,7 +468,7 @@ func (m *AllExecBalance) Reset() { *m = AllExecBalance{} }
func (m *AllExecBalance) String() string { return proto.CompactTextString(m) } func (m *AllExecBalance) String() string { return proto.CompactTextString(m) }
func (*AllExecBalance) ProtoMessage() {} func (*AllExecBalance) ProtoMessage() {}
func (*AllExecBalance) Descriptor() ([]byte, []int) { func (*AllExecBalance) Descriptor() ([]byte, []int) {
return fileDescriptor_8e28828dcb8d24f0, []int{7} return fileDescriptor_8e28828dcb8d24f0, []int{8}
} }
func (m *AllExecBalance) XXX_Unmarshal(b []byte) error { func (m *AllExecBalance) XXX_Unmarshal(b []byte) error {
...@@ -473,7 +520,7 @@ func (m *ReqAllExecBalance) Reset() { *m = ReqAllExecBalance{} } ...@@ -473,7 +520,7 @@ func (m *ReqAllExecBalance) Reset() { *m = ReqAllExecBalance{} }
func (m *ReqAllExecBalance) String() string { return proto.CompactTextString(m) } func (m *ReqAllExecBalance) String() string { return proto.CompactTextString(m) }
func (*ReqAllExecBalance) ProtoMessage() {} func (*ReqAllExecBalance) ProtoMessage() {}
func (*ReqAllExecBalance) Descriptor() ([]byte, []int) { func (*ReqAllExecBalance) Descriptor() ([]byte, []int) {
return fileDescriptor_8e28828dcb8d24f0, []int{8} return fileDescriptor_8e28828dcb8d24f0, []int{9}
} }
func (m *ReqAllExecBalance) XXX_Unmarshal(b []byte) error { func (m *ReqAllExecBalance) XXX_Unmarshal(b []byte) error {
...@@ -534,6 +581,7 @@ func init() { ...@@ -534,6 +581,7 @@ func init() {
proto.RegisterType((*ReceiptExecAccountTransfer)(nil), "types.ReceiptExecAccountTransfer") proto.RegisterType((*ReceiptExecAccountTransfer)(nil), "types.ReceiptExecAccountTransfer")
proto.RegisterType((*ReceiptAccountTransfer)(nil), "types.ReceiptAccountTransfer") proto.RegisterType((*ReceiptAccountTransfer)(nil), "types.ReceiptAccountTransfer")
proto.RegisterType((*ReceiptAccountMint)(nil), "types.ReceiptAccountMint") proto.RegisterType((*ReceiptAccountMint)(nil), "types.ReceiptAccountMint")
proto.RegisterType((*ReceiptAccountBurn)(nil), "types.ReceiptAccountBurn")
proto.RegisterType((*ReqBalance)(nil), "types.ReqBalance") proto.RegisterType((*ReqBalance)(nil), "types.ReqBalance")
proto.RegisterType((*Accounts)(nil), "types.Accounts") proto.RegisterType((*Accounts)(nil), "types.Accounts")
proto.RegisterType((*ExecAccount)(nil), "types.ExecAccount") proto.RegisterType((*ExecAccount)(nil), "types.ExecAccount")
...@@ -544,32 +592,33 @@ func init() { ...@@ -544,32 +592,33 @@ func init() {
func init() { proto.RegisterFile("account.proto", fileDescriptor_8e28828dcb8d24f0) } func init() { proto.RegisterFile("account.proto", fileDescriptor_8e28828dcb8d24f0) }
var fileDescriptor_8e28828dcb8d24f0 = []byte{ var fileDescriptor_8e28828dcb8d24f0 = []byte{
// 427 bytes of a gzipped FileDescriptorProto // 434 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x54, 0xcd, 0x6a, 0x14, 0x41, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x54, 0xcd, 0x6e, 0x13, 0x31,
0x10, 0xa6, 0xf7, 0x27, 0x9b, 0xa9, 0xd5, 0x80, 0x7d, 0x08, 0x4d, 0x30, 0x38, 0xf6, 0x69, 0x0e, 0x10, 0x96, 0xf3, 0xd3, 0x74, 0x27, 0x50, 0x09, 0x1f, 0x2a, 0xab, 0xa2, 0x62, 0xf1, 0x69, 0x0f,
0xb2, 0x0b, 0x8e, 0x2f, 0x90, 0x80, 0xe0, 0x45, 0x84, 0xd6, 0x53, 0x2e, 0xd2, 0xd3, 0xa9, 0x75, 0x28, 0x91, 0x58, 0x5e, 0xa0, 0x91, 0x90, 0xb8, 0x20, 0x24, 0xc3, 0xa9, 0x17, 0xe4, 0x75, 0x27,
0x07, 0x27, 0x3d, 0x93, 0xee, 0x5e, 0x71, 0x7d, 0x00, 0x5f, 0x43, 0xf0, 0x49, 0xa5, 0x6b, 0x7b, 0x24, 0x22, 0xf5, 0x6e, 0x6d, 0x2f, 0x22, 0x3c, 0x00, 0xaf, 0x81, 0xc4, 0x93, 0x22, 0x4f, 0xbc,
0xb2, 0xb3, 0x06, 0x25, 0x07, 0xc1, 0xdb, 0xd4, 0xf7, 0x55, 0xd5, 0xf7, 0x75, 0x55, 0x31, 0xf0, 0xcd, 0x86, 0x0a, 0xd4, 0x03, 0xa8, 0xb7, 0x9d, 0xef, 0x1b, 0xcf, 0xf7, 0xd9, 0x33, 0xb3, 0xf0,
0x58, 0x1b, 0xd3, 0x6e, 0x6c, 0x58, 0x74, 0xae, 0x0d, 0x2d, 0x9f, 0x86, 0x6d, 0x87, 0x5e, 0x7e, 0x58, 0x1b, 0x53, 0xb7, 0x36, 0xcc, 0x1a, 0x57, 0x87, 0x9a, 0x8f, 0xc3, 0xb6, 0x41, 0x2f, 0x3f,
0x86, 0xd9, 0xc5, 0x0e, 0xe7, 0x67, 0x70, 0x6c, 0x36, 0xce, 0xa1, 0x35, 0x5b, 0xc1, 0x72, 0x56, 0xc3, 0xe4, 0x62, 0x87, 0xf3, 0x33, 0x38, 0x36, 0xad, 0x73, 0x68, 0xcd, 0x56, 0xb0, 0x9c, 0x15,
0x4c, 0xd5, 0x5d, 0xcc, 0x05, 0xcc, 0x2a, 0xdd, 0x68, 0x6b, 0x50, 0x8c, 0x72, 0x56, 0x8c, 0x55, 0x63, 0x75, 0x1b, 0x73, 0x01, 0x93, 0x4a, 0x6f, 0xb4, 0x35, 0x28, 0x06, 0x39, 0x2b, 0x86, 0xaa,
0x1f, 0xf2, 0x53, 0x38, 0x5a, 0xb9, 0xf6, 0x1b, 0x5a, 0x31, 0x26, 0x22, 0x45, 0x9c, 0xc3, 0x44, 0x0b, 0xf9, 0x29, 0x1c, 0x2d, 0x5d, 0xfd, 0x0d, 0xad, 0x18, 0x12, 0x91, 0x22, 0xce, 0x61, 0xa4,
0x5f, 0x5f, 0x3b, 0x31, 0xc9, 0x59, 0x91, 0x29, 0xfa, 0x96, 0xdf, 0x19, 0x9c, 0x29, 0x34, 0x58, 0xaf, 0xae, 0x9c, 0x18, 0xe5, 0xac, 0xc8, 0x14, 0x7d, 0xcb, 0xef, 0x0c, 0xce, 0x14, 0x1a, 0x5c,
0x77, 0xe1, 0xf5, 0x57, 0x34, 0x49, 0xf8, 0x83, 0xd3, 0xd6, 0xaf, 0xd0, 0x45, 0x03, 0x18, 0xe1, 0x37, 0xe1, 0xf5, 0x57, 0x34, 0x49, 0xf8, 0x83, 0xd3, 0xd6, 0x2f, 0xd1, 0x45, 0x03, 0x18, 0xe1,
0x58, 0xc6, 0xa8, 0xec, 0x2e, 0xe6, 0x12, 0x26, 0x9d, 0xc3, 0x2f, 0xa4, 0x3e, 0x7f, 0x79, 0xb2, 0x78, 0x8c, 0xd1, 0xb1, 0xdb, 0x98, 0x4b, 0x18, 0x35, 0x0e, 0xbf, 0x90, 0xfa, 0xf4, 0xe5, 0xc9,
0x20, 0xf7, 0x8b, 0xd4, 0x41, 0x11, 0xc7, 0x0b, 0x98, 0xed, 0x0c, 0x07, 0xf2, 0x72, 0x3f, 0xad, 0x8c, 0xdc, 0xcf, 0x52, 0x05, 0x45, 0x1c, 0x2f, 0x60, 0xb2, 0x33, 0x1c, 0xc8, 0xcb, 0xdd, 0xb4,
0xa7, 0xe5, 0x0a, 0x4e, 0x93, 0x8f, 0xdf, 0x3d, 0xf4, 0x3a, 0xec, 0x61, 0x3a, 0xa3, 0xbf, 0xeb, 0x8e, 0x96, 0x4b, 0x38, 0x4d, 0x3e, 0x7e, 0xf7, 0xd0, 0xe9, 0xb0, 0xfb, 0xe9, 0x0c, 0xfe, 0xae,
0x54, 0xc0, 0x0f, 0x75, 0xde, 0xd6, 0x36, 0xfc, 0x63, 0x8d, 0x9f, 0x0c, 0x40, 0xe1, 0xed, 0x65, 0x53, 0x01, 0x3f, 0xd4, 0x79, 0xbb, 0xb6, 0xe1, 0x7f, 0x6b, 0x2c, 0x5a, 0x67, 0xff, 0xb1, 0xc6,
0xda, 0xc7, 0x53, 0xc8, 0xe2, 0xac, 0xd1, 0x7b, 0xf4, 0x82, 0xe5, 0xe3, 0x22, 0x53, 0x7b, 0x20, 0x4f, 0x06, 0xa0, 0xf0, 0x66, 0x91, 0x7a, 0xfe, 0x14, 0xb2, 0xd8, 0x4f, 0xf4, 0x1e, 0xbd, 0x60,
0x6e, 0x2b, 0x8e, 0x14, 0x1d, 0x75, 0xcd, 0x54, 0x8a, 0x62, 0x95, 0x0f, 0x3a, 0xe0, 0x1b, 0xed, 0xf9, 0xb0, 0xc8, 0xd4, 0x1e, 0x88, 0x13, 0x11, 0xdb, 0x86, 0x8e, 0xaa, 0x66, 0x2a, 0x45, 0xf1,
0xd7, 0x34, 0xbc, 0x4c, 0xed, 0x01, 0x7e, 0x0e, 0xa0, 0xbd, 0xc7, 0xf0, 0x31, 0x66, 0xa7, 0x8d, 0x94, 0x0f, 0x3a, 0xe0, 0x1b, 0xed, 0x57, 0xd4, 0xa0, 0x4c, 0xed, 0x01, 0x7e, 0x0e, 0xa0, 0xbd,
0x66, 0x84, 0xc4, 0x35, 0xf2, 0xe7, 0xf0, 0x68, 0x47, 0xfb, 0xed, 0x4d, 0xd5, 0x36, 0x62, 0x4a, 0xc7, 0xf0, 0x31, 0x66, 0xa7, 0xa9, 0xc9, 0x08, 0x89, 0xa3, 0xc2, 0x9f, 0xc3, 0xa3, 0x1d, 0xed,
0x09, 0x73, 0xc2, 0xde, 0x13, 0x24, 0x5f, 0xc0, 0x71, 0x32, 0xee, 0x79, 0x0e, 0x63, 0x6d, 0x0c, 0xb7, 0xd7, 0x55, 0xbd, 0x11, 0x63, 0x4a, 0x98, 0x12, 0xf6, 0x9e, 0x20, 0xf9, 0x02, 0x8e, 0x93,
0x79, 0xbb, 0xff, 0xac, 0x48, 0xc9, 0x77, 0x30, 0x1f, 0xdc, 0xc7, 0xc0, 0x34, 0x3b, 0x30, 0x5d, 0x71, 0xcf, 0x73, 0x18, 0x6a, 0x63, 0xc8, 0xdb, 0xdd, 0x6b, 0x45, 0x4a, 0xbe, 0x83, 0x69, 0x6f,
0xc0, 0x2c, 0xdd, 0xf4, 0x9f, 0x66, 0x94, 0x68, 0x79, 0x05, 0x27, 0x17, 0x4d, 0x13, 0x7b, 0xf6, 0x06, 0x7b, 0xa6, 0xd9, 0x81, 0xe9, 0x02, 0x26, 0x69, 0x6f, 0xfe, 0xf4, 0x46, 0x89, 0x96, 0x97,
0x63, 0xea, 0xcf, 0x93, 0xed, 0xcf, 0x93, 0xbf, 0x3a, 0x90, 0x15, 0x23, 0x32, 0xc8, 0x53, 0xcf, 0x70, 0x72, 0xb1, 0xd9, 0xc4, 0x9a, 0xdd, 0x33, 0x75, 0x2b, 0xc0, 0xf6, 0x2b, 0xc0, 0x5f, 0x1d,
0x01, 0xa3, 0x86, 0x69, 0xf2, 0x07, 0x83, 0x27, 0x0a, 0x6f, 0x1f, 0xd0, 0xff, 0x3f, 0x0d, 0xff, 0xc8, 0x8a, 0x01, 0x19, 0xe4, 0xa9, 0x66, 0x8f, 0x51, 0xfd, 0x34, 0xf9, 0x83, 0xc1, 0x13, 0x85,
0xf2, 0xd9, 0xd5, 0xf9, 0xa7, 0x3a, 0xac, 0x37, 0xd5, 0xc2, 0xb4, 0x37, 0xcb, 0xb2, 0x34, 0x76, 0x37, 0xf7, 0xa8, 0xff, 0x40, 0x8f, 0xbf, 0x78, 0x76, 0x79, 0xfe, 0x69, 0x1d, 0x56, 0x6d, 0x35,
0x69, 0xd6, 0xba, 0xb6, 0x65, 0xb9, 0xa4, 0xb7, 0x55, 0x47, 0xf4, 0x4b, 0x28, 0x7f, 0x05, 0x00, 0x33, 0xf5, 0xf5, 0xbc, 0x2c, 0x8d, 0x9d, 0x9b, 0x95, 0x5e, 0xdb, 0xb2, 0x9c, 0xd3, 0xdd, 0xaa,
0x00, 0xff, 0xff, 0x1b, 0xce, 0xc2, 0x14, 0x23, 0x04, 0x00, 0x00, 0x23, 0xfa, 0xed, 0x94, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x57, 0xdf, 0x86, 0xd3, 0x87, 0x04,
0x00, 0x00,
} }
...@@ -104,6 +104,7 @@ const ( ...@@ -104,6 +104,7 @@ const (
TyLogGenesisDeposit = 12 TyLogGenesisDeposit = 12
TyLogRollback = 13 TyLogRollback = 13
TyLogMint = 14 TyLogMint = 14
TyLogBurn = 15
) )
//SystemLog 系统log日志 //SystemLog 系统log日志
...@@ -121,6 +122,8 @@ var SystemLog = map[int64]*LogInfo{ ...@@ -121,6 +122,8 @@ var SystemLog = map[int64]*LogInfo{
TyLogGenesisTransfer: {reflect.TypeOf(ReceiptAccountTransfer{}), "LogGenesisTransfer"}, TyLogGenesisTransfer: {reflect.TypeOf(ReceiptAccountTransfer{}), "LogGenesisTransfer"},
TyLogGenesisDeposit: {reflect.TypeOf(ReceiptAccountTransfer{}), "LogGenesisDeposit"}, TyLogGenesisDeposit: {reflect.TypeOf(ReceiptAccountTransfer{}), "LogGenesisDeposit"},
TyLogRollback: {reflect.TypeOf(LocalDBSet{}), "LogRollback"}, TyLogRollback: {reflect.TypeOf(LocalDBSet{}), "LogRollback"},
TyLogMint: {reflect.TypeOf(ReceiptAccountMint{}), "LogMint"},
TyLogBurn: {reflect.TypeOf(ReceiptAccountBurn{}), "LogBurn"},
} }
//exec type //exec type
......
...@@ -181,4 +181,7 @@ var ( ...@@ -181,4 +181,7 @@ var (
ErrHeightOverflow = errors.New("ErrHeightOverflow") ErrHeightOverflow = errors.New("ErrHeightOverflow")
ErrRecordBlockSequence = errors.New("ErrRecordBlockSequence") ErrRecordBlockSequence = errors.New("ErrRecordBlockSequence")
ErrExecPanic = errors.New("ErrExecPanic") ErrExecPanic = errors.New("ErrExecPanic")
ErrDisableWrite = errors.New("ErrDisableWrite")
ErrDisableRead = errors.New("ErrDisableRead")
) )
...@@ -41,6 +41,11 @@ message ReceiptAccountMint { ...@@ -41,6 +41,11 @@ message ReceiptAccountMint {
Account current = 2; Account current = 2;
} }
message ReceiptAccountBurn {
Account prev = 1;
Account current = 2;
}
//查询一个地址列表在某个执行器中余额 //查询一个地址列表在某个执行器中余额
message ReqBalance { message ReqBalance {
//地址列表 //地址列表
......
...@@ -205,25 +205,17 @@ func ReportErrEventToFront(logger log.Logger, client queue.Client, frommodule st ...@@ -205,25 +205,17 @@ func ReportErrEventToFront(logger log.Logger, client queue.Client, frommodule st
//DelDupKey 删除重复的key //DelDupKey 删除重复的key
func DelDupKey(kvs []*types.KeyValue) []*types.KeyValue { func DelDupKey(kvs []*types.KeyValue) []*types.KeyValue {
dupindex := make(map[string]int) dupindex := make(map[string]int)
hasdup := false n := 0
for i, kv := range kvs { for _, kv := range kvs {
skey := string(kv.Key) skey := string(kv.Key)
if index, ok := dupindex[skey]; ok { if index, ok := dupindex[skey]; ok {
hasdup = true //重复的key 替换老的key
kvs[index] = nil
}
dupindex[skey] = i
}
//没有重复的情况下,不需要重新处理
if !hasdup {
return kvs
}
index := 0
for _, kv := range kvs {
if kv != nil {
kvs[index] = kv kvs[index] = kv
index++ } else {
dupindex[skey] = n
kvs[n] = kv
n++
} }
} }
return kvs[0:index] return kvs[0:n]
} }
...@@ -225,8 +225,9 @@ func ExecBlock(client queue.Client, prevStateRoot []byte, block *types.Block, er ...@@ -225,8 +225,9 @@ func ExecBlock(client queue.Client, prevStateRoot []byte, block *types.Block, er
//通过consensus module 再次检查 //通过consensus module 再次检查
ulog.Debug("ExecBlock", "height------->", block.Height, "ntx", len(block.Txs)) ulog.Debug("ExecBlock", "height------->", block.Height, "ntx", len(block.Txs))
beg := types.Now() beg := types.Now()
beg2 := beg
defer func() { defer func() {
ulog.Info("ExecBlock", "height", block.Height, "ntx", len(block.Txs), "writebatchsync", sync, "cost", types.Since(beg)) ulog.Info("ExecBlock", "height", block.Height, "ntx", len(block.Txs), "writebatchsync", sync, "cost", types.Since(beg2))
}() }()
if errReturn && block.Height > 0 && !block.CheckSign() { if errReturn && block.Height > 0 && !block.CheckSign() {
...@@ -330,7 +331,6 @@ func ExecBlock(client queue.Client, prevStateRoot []byte, block *types.Block, er ...@@ -330,7 +331,6 @@ func ExecBlock(client queue.Client, prevStateRoot []byte, block *types.Block, er
} }
} }
ulog.Info("ExecBlock", "CheckBlock", types.Since(beg)) ulog.Info("ExecBlock", "CheckBlock", types.Since(beg))
beg = types.Now()
// 写数据库失败时需要及时返回错误,防止错误数据被写入localdb中CHAIN33-567 // 写数据库失败时需要及时返回错误,防止错误数据被写入localdb中CHAIN33-567
err = ExecKVSetCommit(client, block.StateHash) err = ExecKVSetCommit(client, block.StateHash)
if err != nil { if err != nil {
......
...@@ -144,8 +144,8 @@ func TestDelDupKey(t *testing.T) { ...@@ -144,8 +144,8 @@ func TestDelDupKey(t *testing.T) {
{Key: []byte("hello"), Value: []byte("world2")}, {Key: []byte("hello"), Value: []byte("world2")},
} }
result := []*types.KeyValue{ result := []*types.KeyValue{
{Key: []byte("hello1"), Value: []byte("world")},
{Key: []byte("hello"), Value: []byte("world2")}, {Key: []byte("hello"), Value: []byte("world2")},
{Key: []byte("hello1"), Value: []byte("world")},
} }
kvs = DelDupKey(kvs) kvs = DelDupKey(kvs)
assert.Equal(t, kvs, result) assert.Equal(t, kvs, result)
...@@ -173,6 +173,7 @@ func BenchmarkDelDupKey(b *testing.B) { ...@@ -173,6 +173,7 @@ func BenchmarkDelDupKey(b *testing.B) {
kvs = append(kvs, &types.KeyValue{Key: key, Value: value}) kvs = append(kvs, &types.KeyValue{Key: key, Value: value})
} }
} }
b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
testkv := make([]*types.KeyValue, len(kvs)) testkv := make([]*types.KeyValue, len(kvs))
copy(testkv, kvs) copy(testkv, kvs)
......
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