Commit 2c249090 authored by 张振华's avatar 张振华

Merge branch 'master' into guess

parents 335380b0 e26a5b79
...@@ -33,6 +33,8 @@ const ( ...@@ -33,6 +33,8 @@ const (
delAct int64 = 2 //reference blockstore.go, del para block action delAct int64 = 2 //reference blockstore.go, del para block action
paraCrossTxCount = 2 //current only support 2 txs for cross paraCrossTxCount = 2 //current only support 2 txs for cross
minBlockNum = 6 //min block number startHeight before lastHeight in mainchain
) )
var ( var (
...@@ -40,7 +42,6 @@ var ( ...@@ -40,7 +42,6 @@ var (
grpcSite = "localhost:8802" grpcSite = "localhost:8802"
genesisBlockTime int64 = 1514533390 genesisBlockTime int64 = 1514533390
startHeight int64 //parachain sync from startHeight in mainchain startHeight int64 //parachain sync from startHeight in mainchain
searchSeq int64 //start sequence to search startHeight in mainchain
blockSec int64 = 5 //write block interval, second blockSec int64 = 5 //write block interval, second
emptyBlockInterval int64 = 4 //write empty block every interval blocks in mainchain emptyBlockInterval int64 = 4 //write empty block every interval blocks in mainchain
zeroHash [32]byte zeroHash [32]byte
...@@ -75,7 +76,6 @@ func New(cfg *types.Consensus, sub []byte) queue.Module { ...@@ -75,7 +76,6 @@ func New(cfg *types.Consensus, sub []byte) queue.Module {
} }
if cfg.StartHeight > 0 { if cfg.StartHeight > 0 {
startHeight = cfg.StartHeight startHeight = cfg.StartHeight
searchSeq = calcSearchseq(cfg.StartHeight)
} }
if cfg.WriteBlockSeconds > 0 { if cfg.WriteBlockSeconds > 0 {
blockSec = cfg.WriteBlockSeconds blockSec = cfg.WriteBlockSeconds
...@@ -139,13 +139,6 @@ func New(cfg *types.Consensus, sub []byte) queue.Module { ...@@ -139,13 +139,6 @@ func New(cfg *types.Consensus, sub []byte) queue.Module {
return para return para
} }
func calcSearchseq(height int64) int64 {
if height < 1000 {
return 0
}
return height - 1000
}
//para 不检查任何的交易 //para 不检查任何的交易
func (client *client) CheckBlock(parent *types.Block, current *types.BlockDetail) error { func (client *client) CheckBlock(parent *types.Block, current *types.BlockDetail) error {
err := checkMinerTx(current) err := checkMinerTx(current)
...@@ -179,10 +172,7 @@ func (client *client) InitBlock() { ...@@ -179,10 +172,7 @@ func (client *client) InitBlock() {
} }
if block == nil { if block == nil {
startSeq := int64(0) startSeq := client.GetStartSeq(startHeight)
if searchSeq > 0 {
startSeq = client.GetSeqByHeightOnMain(startHeight, searchSeq)
}
// 创世区块 // 创世区块
newblock := &types.Block{} newblock := &types.Block{}
newblock.Height = 0 newblock.Height = 0
...@@ -191,37 +181,47 @@ func (client *client) InitBlock() { ...@@ -191,37 +181,47 @@ func (client *client) InitBlock() {
tx := client.CreateGenesisTx() tx := client.CreateGenesisTx()
newblock.Txs = tx newblock.Txs = tx
newblock.TxHash = merkle.CalcMerkleRoot(newblock.Txs) newblock.TxHash = merkle.CalcMerkleRoot(newblock.Txs)
client.WriteBlock(zeroHash[:], newblock, startSeq-int64(1)) client.WriteBlock(zeroHash[:], newblock, startSeq-1)
} else { } else {
client.SetCurrentBlock(block) client.SetCurrentBlock(block)
} }
} }
func (client *client) GetSeqByHeightOnMain(height int64, originSeq int64) int64 { // GetStartSeq get startSeq in mainchain
lastSeq, err := client.GetLastSeqOnMainChain() func (client *client) GetStartSeq(height int64) int64 {
plog.Info("Searching for the sequence", "heightOnMain", height, "searchSeq", searchSeq, "lastSeq", lastSeq) if height == 0 {
return 0
}
lastHeight, err := client.GetLastHeightOnMainChain()
if err != nil { if err != nil {
panic(err) panic(err)
} }
hint := time.NewTicker(10 * time.Second) if lastHeight < height {
defer hint.Stop() panic(fmt.Sprintf("lastHeight(%d) less than startHeight(%d) in mainchain", lastHeight, height))
for originSeq <= lastSeq { }
hint := time.NewTicker(5 * time.Second)
for lastHeight < height+minBlockNum {
select { select {
case <-hint.C: case <-hint.C:
plog.Info("Still Searching......", "searchAtSeq", originSeq, "lastSeq", lastSeq) plog.Info("Waiting lastHeight increase......", "lastHeight", lastHeight, "startHeight", height)
default: default:
blockDetail, seqTy, err := client.GetBlockOnMainBySeq(originSeq) lastHeight, err = client.GetLastHeightOnMainChain()
if err != nil { if err != nil {
panic(err) panic(err)
} }
if blockDetail.Block.Height == height && seqTy == addAct { time.Sleep(time.Second)
plog.Info("the target sequence in mainchain", "heightOnMain", height, "targetSeq", originSeq)
return originSeq
}
originSeq++
} }
} }
panic("Main chain has not reached the height currently") hint.Stop()
plog.Info(fmt.Sprintf("lastHeight more than %d blocks after startHeight", minBlockNum), "lastHeight", lastHeight, "startHeight", height)
seq, err := client.GetSeqByHeightOnMainChain(height)
if err != nil {
panic(err)
}
plog.Info("the start sequence in mainchain", "startHeight", height, "startSeq", seq)
return seq
} }
func (client *client) CreateGenesisTx() (ret []*types.Transaction) { func (client *client) CreateGenesisTx() (ret []*types.Transaction) {
...@@ -357,6 +357,15 @@ func (client *client) getLastBlockInfo() (int64, *types.Block, []byte, int64, er ...@@ -357,6 +357,15 @@ func (client *client) getLastBlockInfo() (int64, *types.Block, []byte, int64, er
} }
func (client *client) GetLastHeightOnMainChain() (int64, error) {
header, err := client.grpcClient.GetLastHeader(context.Background(), &types.ReqNil{})
if err != nil {
plog.Error("GetLastHeightOnMainChain", "Error", err.Error())
return -1, err
}
return header.Height, nil
}
func (client *client) GetLastSeqOnMainChain() (int64, error) { func (client *client) GetLastSeqOnMainChain() (int64, error) {
seq, err := client.grpcClient.GetLastBlockSequence(context.Background(), &types.ReqNil{}) seq, err := client.grpcClient.GetLastBlockSequence(context.Background(), &types.ReqNil{})
if err != nil { if err != nil {
...@@ -367,6 +376,24 @@ func (client *client) GetLastSeqOnMainChain() (int64, error) { ...@@ -367,6 +376,24 @@ func (client *client) GetLastSeqOnMainChain() (int64, error) {
return seq.Data, nil return seq.Data, nil
} }
func (client *client) GetSeqByHeightOnMainChain(height int64) (int64, error) {
hash, err := client.GetHashByHeightOnMainChain(height)
if err != nil {
return -1, err
}
seq, err := client.GetSeqByHashOnMainChain(hash)
return seq, err
}
func (client *client) GetHashByHeightOnMainChain(height int64) ([]byte, error) {
reply, err := client.grpcClient.GetBlockHash(context.Background(), &types.ReqInt{Height: height})
if err != nil {
plog.Error("GetHashByHeightOnMainChain", "Error", err.Error())
return nil, err
}
return reply.Hash, nil
}
func (client *client) GetSeqByHashOnMainChain(hash []byte) (int64, error) { func (client *client) GetSeqByHashOnMainChain(hash []byte) (int64, error) {
seq, err := client.grpcClient.GetSequenceByHash(context.Background(), &types.ReqHash{Hash: hash}) seq, err := client.grpcClient.GetSequenceByHash(context.Background(), &types.ReqHash{Hash: hash})
if err != nil { if err != nil {
...@@ -465,7 +492,6 @@ func (client *client) RequestTx(currSeq int64, preMainBlockHash []byte) ([]*type ...@@ -465,7 +492,6 @@ func (client *client) RequestTx(currSeq int64, preMainBlockHash []byte) ([]*type
//lastSeq = currSeq-1, main node not update //lastSeq = currSeq-1, main node not update
if lastSeq+1 == currSeq { if lastSeq+1 == currSeq {
plog.Debug("Waiting new sequence from main chain") plog.Debug("Waiting new sequence from main chain")
time.Sleep(time.Second * time.Duration(blockSec*2))
return nil, nil, -1, paracross.ErrParaWaitingNewSeq return nil, nil, -1, paracross.ErrParaWaitingNewSeq
} }
...@@ -596,15 +622,16 @@ func (client *client) CreateBlock() { ...@@ -596,15 +622,16 @@ func (client *client) CreateBlock() {
txs, blockOnMain, seqTy, err := client.RequestTx(currSeq, lastSeqMainHash) txs, blockOnMain, seqTy, err := client.RequestTx(currSeq, lastSeqMainHash)
if err != nil { if err != nil {
incSeqFlag = false
if err == paracross.ErrParaCurHashNotMatch { if err == paracross.ErrParaCurHashNotMatch {
newSeq, newSeqMainHash, err := client.switchHashMatchedBlock(currSeq) newSeq, newSeqMainHash, err := client.switchHashMatchedBlock(currSeq)
if err == nil { if err == nil {
currSeq = newSeq currSeq = newSeq
lastSeqMainHash = newSeqMainHash lastSeqMainHash = newSeqMainHash
continue
} }
} }
incSeqFlag = false time.Sleep(time.Second * time.Duration(blockSec))
time.Sleep(time.Second)
continue continue
} }
......
...@@ -92,6 +92,9 @@ func (s *suiteParaCommitMsg) initEnv(cfg *types.Config, sub *types.ConfigSubModu ...@@ -92,6 +92,9 @@ func (s *suiteParaCommitMsg) initEnv(cfg *types.Config, sub *types.ConfigSubModu
ret := &types.Reply{IsOk: true, Msg: data} ret := &types.Reply{IsOk: true, Msg: data}
s.grpcCli.On("QueryChain", mock.Anything, mock.Anything).Return(ret, nil).Maybe() s.grpcCli.On("QueryChain", mock.Anything, mock.Anything).Return(ret, nil).Maybe()
s.grpcCli.On("SendTransaction", mock.Anything, mock.Anything).Return(reply, nil).Maybe() s.grpcCli.On("SendTransaction", mock.Anything, mock.Anything).Return(reply, nil).Maybe()
s.grpcCli.On("GetLastHeader", mock.Anything, mock.Anything).Return(&types.Header{Height: cfg.Consensus.StartHeight + minBlockNum}, nil).Maybe()
s.grpcCli.On("GetBlockHash", mock.Anything, mock.Anything).Return(&types.ReplyHash{Hash: []byte("1")}, nil).Maybe()
s.grpcCli.On("GetSequenceByHash", mock.Anything, mock.Anything).Return(&types.Int64{Data: cfg.Consensus.StartHeight}, nil).Maybe()
s.para.grpcClient = s.grpcCli s.para.grpcClient = s.grpcCli
s.para.SetQueueClient(q.Client()) s.para.SetQueueClient(q.Client())
......
...@@ -58,7 +58,7 @@ func (s *suiteParaClient) initEnv(cfg *types.Config, sub *types.ConfigSubModule) ...@@ -58,7 +58,7 @@ func (s *suiteParaClient) initEnv(cfg *types.Config, sub *types.ConfigSubModule)
s.store = store.New(cfg.Store, sub.Store) s.store = store.New(cfg.Store, sub.Store)
s.store.SetQueueClient(q.Client()) s.store.SetQueueClient(q.Client())
cfg.Consensus.StartHeight = 0 //cfg.Consensus.StartHeight = 0
cfg.Consensus.EmptyBlockInterval = 1 cfg.Consensus.EmptyBlockInterval = 1
s.para = New(cfg.Consensus, sub.Consensus["para"]).(*client) s.para = New(cfg.Consensus, sub.Consensus["para"]).(*client)
s.grpcCli = &typesmocks.Chain33Client{} s.grpcCli = &typesmocks.Chain33Client{}
...@@ -103,6 +103,8 @@ func (s *suiteParaClient) initEnv(cfg *types.Config, sub *types.ConfigSubModule) ...@@ -103,6 +103,8 @@ func (s *suiteParaClient) initEnv(cfg *types.Config, sub *types.ConfigSubModule)
ret := &types.Reply{IsOk: true, Msg: data} ret := &types.Reply{IsOk: true, Msg: data}
s.grpcCli.On("QueryChain", mock.Anything, mock.Anything).Return(ret, nil).Maybe() s.grpcCli.On("QueryChain", mock.Anything, mock.Anything).Return(ret, nil).Maybe()
s.grpcCli.On("SendTransaction", mock.Anything, mock.Anything).Return(reply, nil).Maybe() s.grpcCli.On("SendTransaction", mock.Anything, mock.Anything).Return(reply, nil).Maybe()
s.grpcCli.On("GetLastHeader", mock.Anything, mock.Anything).Return(&types.Header{Height: cfg.Consensus.StartHeight + minBlockNum}, nil).Maybe()
s.grpcCli.On("GetBlockHash", mock.Anything, mock.Anything).Return(&types.ReplyHash{Hash: []byte("1")}, nil).Maybe()
s.para.grpcClient = s.grpcCli s.para.grpcClient = s.grpcCli
s.para.SetQueueClient(q.Client()) s.para.SetQueueClient(q.Client())
......
...@@ -49,5 +49,4 @@ cli send jsvm call -a "{\"hello\": \"world\"}" -f hello -n test -k 14KEKbYtKKQm ...@@ -49,5 +49,4 @@ cli send jsvm call -a "{\"hello\": \"world\"}" -f hello -n test -k 14KEKbYtKKQm
第四步:query test合约hello函数 第四步:query test合约hello函数
cli jsvm query -a "{\"hello\": \"world\"}" -f hello -n test cli jsvm query -a "{\"hello\": \"world\"}" -f hello -n test
*/ */
...@@ -27,3 +27,18 @@ func (action *Action) GetMainHeightByTxHash(txHash []byte) int64 { ...@@ -27,3 +27,18 @@ func (action *Action) GetMainHeightByTxHash(txHash []byte) int64 {
return -1 return -1
} }
// GetMainBlockHashByHeight get Hash
func (action *Action) GetMainBlockHashByHeight(height int64) ([]byte, error) {
for i := 0; i < retryNum; i++ {
req := &types.ReqInt{Height: height}
replyHash, err := action.grpcClient.GetBlockHash(context.Background(), req)
if err != nil {
time.Sleep(time.Second)
} else {
return replyHash.Hash, nil
}
}
return nil, types.ErrBlockNotFound
}
...@@ -127,6 +127,7 @@ type Action struct { ...@@ -127,6 +127,7 @@ type Action struct {
conn *grpc.ClientConn conn *grpc.ClientConn
grpcClient types.Chain33Client grpcClient types.Chain33Client
index int index int
lottery *Lottery
} }
// NewLotteryAction generate New Action // NewLotteryAction generate New Action
...@@ -135,10 +136,9 @@ func NewLotteryAction(l *Lottery, tx *types.Transaction, index int) *Action { ...@@ -135,10 +136,9 @@ func NewLotteryAction(l *Lottery, tx *types.Transaction, index int) *Action {
fromaddr := tx.From() fromaddr := tx.From()
msgRecvOp := grpc.WithMaxMsgSize(grpcRecSize) msgRecvOp := grpc.WithMaxMsgSize(grpcRecSize)
if types.IsPara() && cfg.ParaRemoteGrpcClient == "" { paraRemoteGrpcClient := types.Conf("config.consensus").GStr("ParaRemoteGrpcClient")
panic("ParaRemoteGrpcClient error")
} conn, err := grpc.Dial(paraRemoteGrpcClient, grpc.WithInsecure(), msgRecvOp)
conn, err := grpc.Dial(cfg.ParaRemoteGrpcClient, grpc.WithInsecure(), msgRecvOp)
if err != nil { if err != nil {
panic(err) panic(err)
...@@ -146,7 +146,7 @@ func NewLotteryAction(l *Lottery, tx *types.Transaction, index int) *Action { ...@@ -146,7 +146,7 @@ func NewLotteryAction(l *Lottery, tx *types.Transaction, index int) *Action {
grpcClient := types.NewChain33Client(conn) grpcClient := types.NewChain33Client(conn)
return &Action{l.GetCoinsAccount(), l.GetStateDB(), hash, fromaddr, l.GetBlockTime(), return &Action{l.GetCoinsAccount(), l.GetStateDB(), hash, fromaddr, l.GetBlockTime(),
l.GetHeight(), dapp.ExecAddress(string(tx.Execer)), l.GetDifficulty(), l.GetAPI(), conn, grpcClient, index} l.GetHeight(), dapp.ExecAddress(string(tx.Execer)), l.GetDifficulty(), l.GetAPI(), conn, grpcClient, index, l}
} }
// GetLottCommonRecipt generate logs for lottery common action // GetLottCommonRecipt generate logs for lottery common action
...@@ -569,7 +569,6 @@ func (action *Action) LotteryClose(draw *pty.LotteryClose) (*types.Receipt, erro ...@@ -569,7 +569,6 @@ func (action *Action) LotteryClose(draw *pty.LotteryClose) (*types.Receipt, erro
func (action *Action) findLuckyNum(isSolo bool, lott *LotteryDB) int64 { func (action *Action) findLuckyNum(isSolo bool, lott *LotteryDB) int64 {
var num int64 var num int64
var msg types.Message var msg types.Message
var err error
var hash []byte var hash []byte
if isSolo { if isSolo {
//used for internal verification //used for internal verification
...@@ -579,7 +578,12 @@ func (action *Action) findLuckyNum(isSolo bool, lott *LotteryDB) int64 { ...@@ -579,7 +578,12 @@ func (action *Action) findLuckyNum(isSolo bool, lott *LotteryDB) int64 {
//在主链上,当前高度查询不到,如果要保证区块个数,高度传入action.height-1 //在主链上,当前高度查询不到,如果要保证区块个数,高度传入action.height-1
llog.Debug("findLuckyNum on randnum module") llog.Debug("findLuckyNum on randnum module")
if !types.IsPara() { if !types.IsPara() {
req := &types.ReqRandHash{ExecName: "ticket", Height: action.height - 1, BlockNum: blockNum} blockHash, err := action.api.GetBlockHash(&types.ReqInt{Height: action.height - 1})
if err != nil {
return -1
}
req := &types.ReqRandHash{ExecName: "ticket", Hash: blockHash.Hash, BlockNum: blockNum}
msg, err = action.api.Query("ticket", "RandNumHash", req) msg, err = action.api.Query("ticket", "RandNumHash", req)
if err != nil { if err != nil {
return -1 return -1
...@@ -587,12 +591,20 @@ func (action *Action) findLuckyNum(isSolo bool, lott *LotteryDB) int64 { ...@@ -587,12 +591,20 @@ func (action *Action) findLuckyNum(isSolo bool, lott *LotteryDB) int64 {
reply := msg.(*types.ReplyHash) reply := msg.(*types.ReplyHash)
hash = reply.Hash hash = reply.Hash
} else { } else {
mainHeight := action.GetMainHeightByTxHash(action.txhash) txs := action.lottery.GetTxs()
if mainHeight < 0 { if len(txs) < action.index+1 {
llog.Error("findLuckyNum", "mainHeight", mainHeight) llog.Error("findLuckyNum", "len(txs)", len(txs), "index", action.index)
return -1 return -1
} }
req := &types.ReqRandHash{ExecName: "ticket", Height: mainHeight, BlockNum: blockNum}
msg, err := action.api.Query("paracross", "GetMainBlockHash", txs[0])
if err != nil {
return -1
}
queryReply := msg.(*types.ReplyHash)
mainBlockHash := queryReply.Hash
req := &types.ReqRandHash{ExecName: "ticket", Hash: mainBlockHash, BlockNum: blockNum}
reply, err := action.grpcClient.QueryRandNum(context.Background(), req) reply, err := action.grpcClient.QueryRandNum(context.Background(), req)
if err != nil { if err != nil {
return -1 return -1
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"strings" "strings"
"github.com/33cn/chain33/rpc/jsonclient" "github.com/33cn/chain33/rpc/jsonclient"
"github.com/33cn/chain33/system/dapp/commands"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
pt "github.com/33cn/plugin/plugin/dapp/paracross/types" pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -162,19 +163,12 @@ func addCreateTransferFlags(cmd *cobra.Command) { ...@@ -162,19 +163,12 @@ func addCreateTransferFlags(cmd *cobra.Command) {
cmd.Flags().StringP("note", "n", "", "transaction note info") cmd.Flags().StringP("note", "n", "", "transaction note info")
cmd.Flags().StringP("title", "", "", "the title of para chain, like `p.user.guodun.`")
cmd.MarkFlagRequired("title")
cmd.Flags().StringP("symbol", "s", "", "default for bty, symbol for token") cmd.Flags().StringP("symbol", "s", "", "default for bty, symbol for token")
cmd.MarkFlagRequired("symbol")
} }
func createTransfer(cmd *cobra.Command, args []string) { func createTransfer(cmd *cobra.Command, args []string) {
txHex, err := createTransferTx(cmd, false) commands.CreateAssetTransfer(cmd, args, pt.ParaX)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
fmt.Println(txHex)
} }
//CreateRawTransferToExecCmd create raw transfer to exec tx //CreateRawTransferToExecCmd create raw transfer to exec tx
...@@ -189,27 +183,20 @@ func CreateRawTransferToExecCmd() *cobra.Command { ...@@ -189,27 +183,20 @@ func CreateRawTransferToExecCmd() *cobra.Command {
} }
func addCreateTransferToExecFlags(cmd *cobra.Command) { func addCreateTransferToExecFlags(cmd *cobra.Command) {
cmd.Flags().StringP("to", "t", "", "receiver exec name")
cmd.MarkFlagRequired("to")
cmd.Flags().Float64P("amount", "a", 0, "transaction amount") cmd.Flags().Float64P("amount", "a", 0, "transaction amount")
cmd.MarkFlagRequired("amount") cmd.MarkFlagRequired("amount")
cmd.Flags().StringP("note", "n", "", "transaction note info") cmd.Flags().StringP("note", "n", "", "transaction note info")
cmd.Flags().StringP("title", "", "", "the title of para chain, like `p.user.guodun.`") cmd.Flags().StringP("symbol", "s", "coins.bty", "default for bty, symbol for token")
cmd.MarkFlagRequired("title") cmd.MarkFlagRequired("symbol")
cmd.Flags().StringP("symbol", "s", "", "default for bty, symbol for token") cmd.Flags().StringP("exec", "e", "", "asset deposit exec")
cmd.MarkFlagRequired("exec")
} }
func createTransferToExec(cmd *cobra.Command, args []string) { func createTransferToExec(cmd *cobra.Command, args []string) {
txHex, err := createTransferTx(cmd, false) commands.CreateAssetSendToExec(cmd, args, pt.ParaX)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
fmt.Println(txHex)
} }
//CreateRawWithdrawCmd create raw withdraw tx //CreateRawWithdrawCmd create raw withdraw tx
...@@ -229,59 +216,15 @@ func addCreateWithdrawFlags(cmd *cobra.Command) { ...@@ -229,59 +216,15 @@ func addCreateWithdrawFlags(cmd *cobra.Command) {
cmd.Flags().StringP("note", "n", "", "transaction note info") cmd.Flags().StringP("note", "n", "", "transaction note info")
cmd.Flags().StringP("title", "", "", "the title of para chain, like `p.user.guodun.`")
cmd.MarkFlagRequired("title")
cmd.Flags().StringP("from", "t", "", "exec name")
cmd.MarkFlagRequired("from")
cmd.Flags().StringP("symbol", "s", "", "default for bty, symbol for token") cmd.Flags().StringP("symbol", "s", "", "default for bty, symbol for token")
} cmd.MarkFlagRequired("symbol")
func createWithdraw(cmd *cobra.Command, args []string) { cmd.Flags().StringP("exec", "e", "", "asset deposit exec")
txHex, err := createTransferTx(cmd, true) cmd.MarkFlagRequired("exec")
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
fmt.Println(txHex)
} }
func createTransferTx(cmd *cobra.Command, isWithdraw bool) (string, error) { func createWithdraw(cmd *cobra.Command, args []string) {
amount, _ := cmd.Flags().GetFloat64("amount") commands.CreateAssetWithdraw(cmd, args, pt.ParaX)
if amount < 0 {
return "", types.ErrAmount
}
amountInt64 := int64(math.Trunc((amount+0.0000001)*1e4)) * 1e4
toAddr, _ := cmd.Flags().GetString("to")
note, _ := cmd.Flags().GetString("note")
symbol, _ := cmd.Flags().GetString("symbol")
title, _ := cmd.Flags().GetString("title")
if !strings.HasPrefix(title, "user.p") {
fmt.Fprintln(os.Stderr, "title is not right, title format like `user.p.guodun.`")
return "", types.ErrInvalidParam
}
execName := title + pt.ParaX
param := types.CreateTx{
To: toAddr,
Amount: amountInt64,
Fee: 0,
Note: []byte(note),
IsWithdraw: isWithdraw,
IsToken: false,
TokenSymbol: symbol,
ExecName: execName,
}
tx, err := pt.CreateRawTransferTx(&param)
if err != nil {
return "", err
}
txHex := types.Encode(tx)
return hex.EncodeToString(txHex), nil
} }
// IsSyncCmd query parachain is sync // IsSyncCmd query parachain is sync
......
...@@ -40,6 +40,38 @@ func (p *Paracross) Query_GetAssetTxResult(in *types.ReqHash) (types.Message, er ...@@ -40,6 +40,38 @@ func (p *Paracross) Query_GetAssetTxResult(in *types.ReqHash) (types.Message, er
return p.paracrossGetAssetTxResult(in.Hash) return p.paracrossGetAssetTxResult(in.Hash)
} }
// Query_GetMainBlockHash query get mainblockHash by tx
func (p *Paracross) Query_GetMainBlockHash(in *types.Transaction) (types.Message, error) {
if in == nil {
return nil, types.ErrInvalidParam
}
return p.paracrossGetMainBlockHash(in)
}
func (p *Paracross) paracrossGetMainBlockHash(tx *types.Transaction) (types.Message, error) {
var paraAction pt.ParacrossAction
err := types.Decode(tx.GetPayload(), &paraAction)
if err != nil {
return nil, err
}
if paraAction.GetTy() != pt.ParacrossActionMiner {
return nil, types.ErrCoinBaseTxType
}
if paraAction.GetMiner() == nil {
return nil, pt.ErrParaEmptyMinerTx
}
paraNodeStatus := paraAction.GetMiner().GetStatus()
if paraNodeStatus == nil {
return nil, types.ErrCoinBaseTxType
}
mainHashFromNode := paraNodeStatus.MainBlockHash
return &types.ReplyHash{Hash: mainHashFromNode}, nil
}
func (p *Paracross) paracrossGetHeight(title string) (types.Message, error) { func (p *Paracross) paracrossGetHeight(title string) (types.Message, error) {
ret, err := getTitle(p.GetStateDB(), calcTitleKey(title)) ret, err := getTitle(p.GetStateDB(), calcTitleKey(title))
if err != nil { if err != nil {
......
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
package types package types
import ( import (
fmt "fmt" "encoding/json"
"fmt"
"github.com/33cn/chain33/common/address" "github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/log/log15" "github.com/33cn/chain33/common/log/log15"
...@@ -187,34 +188,28 @@ func CreateRawMinerTx(status *ParacrossNodeStatus) (*types.Transaction, error) { ...@@ -187,34 +188,28 @@ func CreateRawMinerTx(status *ParacrossNodeStatus) (*types.Transaction, error) {
} }
// CreateRawTransferTx create paracross asset transfer tx with transfer and withdraw // CreateRawTransferTx create paracross asset transfer tx with transfer and withdraw
func CreateRawTransferTx(param *types.CreateTx) (*types.Transaction, error) { func (p ParacrossType) CreateRawTransferTx(action string, param json.RawMessage) (*types.Transaction, error) {
if !types.IsParaExecName(param.GetExecName()) { tlog.Error("ParacrossType CreateTx failed", "action", action, "msg", string(param))
tlog.Error("CreateRawTransferTx", "exec", param.GetExecName()) tx, err := p.ExecTypeBase.CreateTx(action, param)
return nil, types.ErrInvalidParam
}
transfer := &ParacrossAction{}
if !param.IsWithdraw {
v := &ParacrossAction_Transfer{Transfer: &types.AssetsTransfer{
Amount: param.Amount, Note: param.GetNote(), To: param.GetTo(), Cointoken: param.TokenSymbol}}
transfer.Value = v
transfer.Ty = ParacrossActionTransfer
} else {
v := &ParacrossAction_Withdraw{Withdraw: &types.AssetsWithdraw{
Amount: param.Amount, Note: param.GetNote(), To: param.GetTo(), Cointoken: param.TokenSymbol}}
transfer.Value = v
transfer.Ty = ParacrossActionWithdraw
}
tx := &types.Transaction{
Execer: []byte(param.GetExecName()),
Payload: types.Encode(transfer),
To: address.ExecAddress(param.GetExecName()),
Fee: param.Fee,
}
var err error
tx, err = types.FormatTx(param.GetExecName(), tx)
if err != nil { if err != nil {
tlog.Error("ParacrossType CreateTx failed", "err", err, "action", action, "msg", string(param))
return nil, err return nil, err
} }
if !types.IsPara() {
var transfer ParacrossAction
err = types.Decode(tx.Payload, &transfer)
if err != nil {
tlog.Error("ParacrossType CreateTx failed", "decode payload err", err, "action", action, "msg", string(param))
return nil, err
}
if action == "Transfer" {
tx.To = transfer.GetTransfer().To
} else if action == "Withdraw" {
tx.To = transfer.GetWithdraw().To
} else if action == "TransferToExec" {
tx.To = transfer.GetTransferToExec().To
}
}
return tx, nil return tx, nil
} }
...@@ -98,15 +98,16 @@ func (p ParacrossType) CreateTx(action string, message json.RawMessage) (*types. ...@@ -98,15 +98,16 @@ func (p ParacrossType) CreateTx(action string, message json.RawMessage) (*types.
} }
return CreateRawAssetTransferTx(&param) return CreateRawAssetTransferTx(&param)
} else if action == "ParacrossTransfer" || action == "ParacrossWithdraw" || action == "ParacrossTransferToExec" { } else if action == "ParacrossTransfer" || action == "Transfer" ||
action == "ParacrossWithdraw" || action == "Withdraw" ||
action == "ParacrossTransferToExec" || action == "TransferToExec" {
var param types.CreateTx var param types.CreateTx
err := json.Unmarshal(message, &param) err := json.Unmarshal(message, &param)
if err != nil { if err != nil {
glog.Error("CreateTx", "Error", err) glog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam return nil, types.ErrInvalidParam
} }
return CreateRawTransferTx(&param) return p.CreateRawTransferTx(action, message)
} }
return nil, types.ErrNotSupport return nil, types.ErrNotSupport
......
...@@ -28,6 +28,7 @@ func PokerBullCmd() *cobra.Command { ...@@ -28,6 +28,7 @@ func PokerBullCmd() *cobra.Command {
PokerBullContinueRawTxCmd(), PokerBullContinueRawTxCmd(),
PokerBullQuitRawTxCmd(), PokerBullQuitRawTxCmd(),
PokerBullQueryResultRawTxCmd(), PokerBullQueryResultRawTxCmd(),
PokerBullPlayRawTxCmd(),
) )
return cmd return cmd
...@@ -45,7 +46,7 @@ func PokerBullStartRawTxCmd() *cobra.Command { ...@@ -45,7 +46,7 @@ func PokerBullStartRawTxCmd() *cobra.Command {
} }
func addPokerbullStartFlags(cmd *cobra.Command) { func addPokerbullStartFlags(cmd *cobra.Command) {
cmd.Flags().Uint64P("value", "a", 0, "value") cmd.Flags().Uint64P("value", "v", 0, "value")
cmd.MarkFlagRequired("value") cmd.MarkFlagRequired("value")
cmd.Flags().Uint32P("playerCount", "p", 0, "player count") cmd.Flags().Uint32P("playerCount", "p", 0, "player count")
...@@ -121,7 +122,7 @@ func pokerbullQuit(cmd *cobra.Command, args []string) { ...@@ -121,7 +122,7 @@ func pokerbullQuit(cmd *cobra.Command, args []string) {
params := &rpctypes.CreateTxIn{ params := &rpctypes.CreateTxIn{
Execer: types.ExecName(pkt.PokerBullX), Execer: types.ExecName(pkt.PokerBullX),
ActionName: pkt.CreatequitTx, ActionName: pkt.CreateQuitTx,
Payload: []byte(fmt.Sprintf("{\"gameId\":\"%s\"}", gameID)), Payload: []byte(fmt.Sprintf("{\"gameId\":\"%s\"}", gameID)),
} }
...@@ -130,6 +131,54 @@ func pokerbullQuit(cmd *cobra.Command, args []string) { ...@@ -130,6 +131,54 @@ func pokerbullQuit(cmd *cobra.Command, args []string) {
ctx.RunWithoutMarshal() ctx.RunWithoutMarshal()
} }
// PokerBullPlayRawTxCmd 生成已匹配玩家游戏命令行
func PokerBullPlayRawTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "play",
Short: "Play game",
Run: pokerbullPlay,
}
addPokerbullPlayFlags(cmd)
return cmd
}
func addPokerbullPlayFlags(cmd *cobra.Command) {
cmd.Flags().StringP("gameID", "g", "", "game ID")
cmd.MarkFlagRequired("gameID")
cmd.Flags().Uint32P("round", "r", 0, "round")
cmd.MarkFlagRequired("round")
cmd.Flags().Uint64P("value", "v", 0, "value")
cmd.MarkFlagRequired("value")
cmd.Flags().StringArrayP("address", "a", nil, "address")
cmd.MarkFlagRequired("address")
}
func pokerbullPlay(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
gameID, _ := cmd.Flags().GetString("gameID")
round, _ := cmd.Flags().GetUint32("round")
value, _ := cmd.Flags().GetUint64("value")
address, _ := cmd.Flags().GetStringArray("address")
payload := &pkt.PBGamePlay{
GameId: gameID,
Value: int64(value) * types.Coin,
Round: int32(round),
}
payload.Address = make([]string, len(address))
copy(payload.Address, address)
params := &rpctypes.CreateTxIn{
Execer: types.ExecName(pkt.PokerBullX),
ActionName: pkt.CreatePlayTx,
Payload: types.MustPBToJSON(payload),
}
var res string
ctx := jsonrpc.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, &res)
ctx.RunWithoutMarshal()
}
// PokerBullQueryResultRawTxCmd 查询命令行 // PokerBullQueryResultRawTxCmd 查询命令行
func PokerBullQueryResultRawTxCmd() *cobra.Command { func PokerBullQueryResultRawTxCmd() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
......
...@@ -26,3 +26,9 @@ func (c *PokerBull) Exec_Quit(payload *pkt.PBGameQuit, tx *types.Transaction, in ...@@ -26,3 +26,9 @@ func (c *PokerBull) Exec_Quit(payload *pkt.PBGameQuit, tx *types.Transaction, in
action := NewAction(c, tx, index) action := NewAction(c, tx, index)
return action.GameQuit(payload) return action.GameQuit(payload)
} }
// Exec_Play 已匹配玩家直接开始游戏
func (c *PokerBull) Exec_Play(payload *pkt.PBGamePlay, tx *types.Transaction, index int) (*types.Receipt, error) {
action := NewAction(c, tx, index)
return action.GamePlay(payload)
}
...@@ -57,7 +57,7 @@ func (c *PokerBull) execLocal(receipt *types.ReceiptData) (*types.LocalDBSet, er ...@@ -57,7 +57,7 @@ func (c *PokerBull) execLocal(receipt *types.ReceiptData) (*types.LocalDBSet, er
dbSet := &types.LocalDBSet{} dbSet := &types.LocalDBSet{}
for i := 0; i < len(receipt.Logs); i++ { for i := 0; i < len(receipt.Logs); i++ {
item := receipt.Logs[i] item := receipt.Logs[i]
if item.Ty == pkt.TyLogPBGameStart || item.Ty == pkt.TyLogPBGameContinue || item.Ty == pkt.TyLogPBGameQuit { if item.Ty == pkt.TyLogPBGameStart || item.Ty == pkt.TyLogPBGameContinue || item.Ty == pkt.TyLogPBGameQuit || item.Ty == pkt.TyLogPBGamePlay {
var Gamelog pkt.ReceiptPBGame var Gamelog pkt.ReceiptPBGame
err := types.Decode(item.Log, &Gamelog) err := types.Decode(item.Log, &Gamelog)
if err != nil { if err != nil {
...@@ -84,3 +84,8 @@ func (c *PokerBull) ExecLocal_Continue(payload *pkt.PBGameContinue, tx *types.Tr ...@@ -84,3 +84,8 @@ func (c *PokerBull) ExecLocal_Continue(payload *pkt.PBGameContinue, tx *types.Tr
func (c *PokerBull) ExecLocal_Quit(payload *pkt.PBGameQuit, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) { func (c *PokerBull) ExecLocal_Quit(payload *pkt.PBGameQuit, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(receiptData) return c.execLocal(receiptData)
} }
// ExecLocal_Play 已匹配游戏交易local执行
func (c *PokerBull) ExecLocal_Play(payload *pkt.PBGamePlay, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
return c.execLocal(receiptData)
}
...@@ -6,7 +6,7 @@ package types; ...@@ -6,7 +6,7 @@ package types;
message PokerBull { message PokerBull {
string gameId = 1; //默认是由创建这局游戏的txHash作为gameId string gameId = 1; //默认是由创建这局游戏的txHash作为gameId
int32 status = 2; // Start 1 -> Continue 2 -> Quit 3 int32 status = 2; // Start 1 -> Continue 2 -> Quit 3
int64 startTime = 3; //开始时间 string startTime = 3; //开始时间
string startTxHash = 4; //游戏启动交易hash string startTxHash = 4; //游戏启动交易hash
int64 value = 5; //赌注 int64 value = 5; //赌注
PBPoker poker = 6; //扑克牌 PBPoker poker = 6; //扑克牌
...@@ -15,7 +15,7 @@ message PokerBull { ...@@ -15,7 +15,7 @@ message PokerBull {
repeated PBResult results = 9; //游戏结果集 repeated PBResult results = 9; //游戏结果集
int64 index = 10; //索引 int64 index = 10; //索引
int64 prevIndex = 11; //上级索引 int64 prevIndex = 11; //上级索引
int64 quitTime = 12; //游戏结束时间 string quitTime = 12; //游戏结束时间
string quitTxHash = 13; //游戏结束交易hash string quitTxHash = 13; //游戏结束交易hash
string dealerAddr = 14; //下局庄家地址 string dealerAddr = 14; //下局庄家地址
bool isWaiting = 15; //游戏是否处于等待状态 bool isWaiting = 15; //游戏是否处于等待状态
...@@ -25,19 +25,21 @@ message PokerBull { ...@@ -25,19 +25,21 @@ message PokerBull {
//一把牌 //一把牌
message PBHand { message PBHand {
repeated int32 cards = 1; //一把牌,五张 repeated int32 cards = 1; //一把牌,五张
int32 result = 2; //斗牛结果 (没牛:0, 牛1-9:1-9, 牛牛:10) int32 result = 2; //斗牛结果 (没牛:0, 牛1-9:1-9, 牛牛:10)
string address = 3; //玩家地址 string address = 3; //玩家地址
bool isWin = 4; //是否赢庄家 bool isWin = 4; //是否赢庄家
int32 leverage = 5; //赌注倍数 int32 leverage = 5; //赌注倍数
string roundTime = 6; //本回合开始时间
} }
//玩家 //玩家
message PBPlayer { message PBPlayer {
repeated PBHand hands = 1; //历史发牌和斗牛结果 repeated PBHand hands = 1; //历史发牌和斗牛结果
string address = 2; //玩家地址 string address = 2; //玩家地址
int64 txHash = 3; //发牌随机数因子txhash的整数格式 int64 txHash = 3; //发牌随机数因子txhash的整数格式
bool ready = 4; // continue状态下,是否ready bool ready = 4; //continue状态下,是否ready
string matchTime = 5; //玩家匹配时间
} }
//本局游戏结果 //本局游戏结果
...@@ -58,10 +60,11 @@ message PBPoker { ...@@ -58,10 +60,11 @@ message PBPoker {
//游戏状态 //游戏状态
message PBGameAction { message PBGameAction {
oneof value { oneof value {
PBGameStart start = 1; PBGameStart start = 1;
PBGameContinue continue = 2; PBGameContinue continue = 2;
PBGameQuit quit = 3; PBGameQuit quit = 3;
PBGameQuery query = 4; PBGameQuery query = 4;
PBGamePlay play = 5;
} }
int32 ty = 10; int32 ty = 10;
} }
...@@ -87,6 +90,14 @@ message PBGameQuery { ...@@ -87,6 +90,14 @@ message PBGameQuery {
string gameId = 1; string gameId = 1;
} }
//已匹配玩家直接游戏
message PBGamePlay {
string gameId = 1; //游戏id
int32 round = 2; //当前游戏回合数
int64 value = 3; //当前游戏赌注
repeated string address = 4; //玩家地址
}
//根据状态和游戏人数查找 //根据状态和游戏人数查找
message QueryPBGameListByStatusAndPlayerNum { message QueryPBGameListByStatusAndPlayerNum {
int32 status = 1; int32 status = 1;
......
...@@ -97,7 +97,7 @@ func testQuitRawTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error { ...@@ -97,7 +97,7 @@ func testQuitRawTxCmd(t *testing.T, jrpc *jsonclient.JSONClient) error {
payload := &pty.PBGameQuit{GameId: "123"} payload := &pty.PBGameQuit{GameId: "123"}
params := &rpctypes.CreateTxIn{ params := &rpctypes.CreateTxIn{
Execer: types.ExecName(pty.PokerBullX), Execer: types.ExecName(pty.PokerBullX),
ActionName: pty.CreatequitTx, ActionName: pty.CreateQuitTx,
Payload: types.MustPBToJSON(payload), Payload: types.MustPBToJSON(payload),
} }
var res string var res string
......
...@@ -12,6 +12,7 @@ const ( ...@@ -12,6 +12,7 @@ const (
PBGameActionContinue PBGameActionContinue
PBGameActionQuit PBGameActionQuit
PBGameActionQuery PBGameActionQuery
PBGameActionPlay
) )
const ( const (
...@@ -30,6 +31,8 @@ const ( ...@@ -30,6 +31,8 @@ const (
TyLogPBGameQuit = 723 TyLogPBGameQuit = 723
// TyLogPBGameQuery log for query PBgame // TyLogPBGameQuery log for query PBgame
TyLogPBGameQuery = 724 TyLogPBGameQuery = 724
// TyLogPBGamePlay log for play PBgame
TyLogPBGamePlay = 725
) )
//包的名字可以通过配置文件来配置 //包的名字可以通过配置文件来配置
...@@ -56,8 +59,10 @@ const ( ...@@ -56,8 +59,10 @@ const (
CreateStartTx = "Start" CreateStartTx = "Start"
// CreateContinueTx 创建继续交易 // CreateContinueTx 创建继续交易
CreateContinueTx = "Continue" CreateContinueTx = "Continue"
// CreatequitTx 创建退出交易 // CreateQuitTx 创建退出交易
CreatequitTx = "Quit" CreateQuitTx = "Quit"
// CreatePlayTx 创建已匹配玩家交易
CreatePlayTx = "Play"
) )
const ( const (
...@@ -67,6 +72,8 @@ const ( ...@@ -67,6 +72,8 @@ const (
DefaultCount = int32(20) DefaultCount = int32(20)
// MaxPlayerNum 最大玩家数 // MaxPlayerNum 最大玩家数
MaxPlayerNum = 5 MaxPlayerNum = 5
// MinPlayerNum 最小玩家数
MinPlayerNum = 2
// MinPlayValue 最小赌注 // MinPlayValue 最小赌注
MinPlayValue = 10 * types.Coin MinPlayValue = 10 * types.Coin
// DefaultStyle 默认游戏类型 // DefaultStyle 默认游戏类型
...@@ -80,5 +87,7 @@ const ( ...@@ -80,5 +87,7 @@ const (
// DeveloperFee 开发者佣金 // DeveloperFee 开发者佣金
DeveloperFee = int64(0.005 * float64(types.Coin)) DeveloperFee = int64(0.005 * float64(types.Coin))
// WinnerReturn 赢家回报率 // WinnerReturn 赢家回报率
WinnerReturn = types.Coin - DeveloperFee WinnerReturn = types.Coin - DeveloperFee - PlatformFee
// PlatformSignAddress 平台签名地址
PlatformSignAddress = "1Geb4ppNiAwMKKyrJgcis3JA57FkqsXvdR"
) )
This diff is collapsed.
...@@ -46,6 +46,7 @@ func (t *PokerBullType) GetTypeMap() map[string]int32 { ...@@ -46,6 +46,7 @@ func (t *PokerBullType) GetTypeMap() map[string]int32 {
"Continue": PBGameActionContinue, "Continue": PBGameActionContinue,
"Quit": PBGameActionQuit, "Quit": PBGameActionQuit,
"Query": PBGameActionQuery, "Query": PBGameActionQuery,
"Play": PBGameActionPlay,
} }
} }
...@@ -56,5 +57,6 @@ func (t *PokerBullType) GetLogMap() map[int64]*types.LogInfo { ...@@ -56,5 +57,6 @@ func (t *PokerBullType) GetLogMap() map[int64]*types.LogInfo {
TyLogPBGameContinue: {Ty: reflect.TypeOf(ReceiptPBGame{}), Name: "TyLogPBGameContinue"}, TyLogPBGameContinue: {Ty: reflect.TypeOf(ReceiptPBGame{}), Name: "TyLogPBGameContinue"},
TyLogPBGameQuit: {Ty: reflect.TypeOf(ReceiptPBGame{}), Name: "TyLogPBGameQuit"}, TyLogPBGameQuit: {Ty: reflect.TypeOf(ReceiptPBGame{}), Name: "TyLogPBGameQuit"},
TyLogPBGameQuery: {Ty: reflect.TypeOf(ReceiptPBGame{}), Name: "TyLogPBGameQuery"}, TyLogPBGameQuery: {Ty: reflect.TypeOf(ReceiptPBGame{}), Name: "TyLogPBGameQuery"},
TyLogPBGamePlay: {Ty: reflect.TypeOf(ReceiptPBGame{}), Name: "TyLogPBGamePlay"},
} }
} }
...@@ -47,5 +47,5 @@ func (ticket *Ticket) Query_MinerSourceList(param *types.ReqString) (types.Messa ...@@ -47,5 +47,5 @@ func (ticket *Ticket) Query_MinerSourceList(param *types.ReqString) (types.Messa
// Query_RandNumHash query randnumhash // Query_RandNumHash query randnumhash
func (ticket *Ticket) Query_RandNumHash(param *types.ReqRandHash) (types.Message, error) { func (ticket *Ticket) Query_RandNumHash(param *types.ReqRandHash) (types.Message, error) {
return ticket.GetRandNum(param.Height, param.BlockNum) return ticket.GetRandNum(param.Hash, param.BlockNum)
} }
...@@ -18,19 +18,20 @@ const ( ...@@ -18,19 +18,20 @@ const (
) )
// GetRandNum for ticket executor // GetRandNum for ticket executor
func (ticket *Ticket) GetRandNum(height int64, blockNum int64) (types.Message, error) { func (ticket *Ticket) GetRandNum(blockHash []byte, blockNum int64) (types.Message, error) {
tlog.Debug("GetRandNum", "height", height, "blockNum", blockNum) tlog.Debug("GetRandNum", "blockHash", blockHash, "blockNum", blockNum)
if blockNum < minBlockNum { if blockNum < minBlockNum {
blockNum = minBlockNum blockNum = minBlockNum
} else if blockNum > maxBlockNum { } else if blockNum > maxBlockNum {
blockNum = maxBlockNum blockNum = maxBlockNum
} }
if blockNum >= height { if len(blockHash) == 0 {
return nil, types.ErrNotFound return nil, types.ErrBlockNotFound
} }
txActions, err := ticket.getTxActions(height, blockNum) txActions, err := ticket.getTxActions(blockHash, blockNum)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -54,20 +55,36 @@ func (ticket *Ticket) GetRandNum(height int64, blockNum int64) (types.Message, e ...@@ -54,20 +55,36 @@ func (ticket *Ticket) GetRandNum(height int64, blockNum int64) (types.Message, e
return &types.ReplyHash{Hash: modify}, nil return &types.ReplyHash{Hash: modify}, nil
} }
func (ticket *Ticket) getTxActions(height int64, blockNum int64) ([]*tickettypes.TicketAction, error) { func (ticket *Ticket) getTxActions(blockHash []byte, blockNum int64) ([]*tickettypes.TicketAction, error) {
var txActions []*tickettypes.TicketAction var txActions []*tickettypes.TicketAction
var reqHashes types.ReqHashes
currHash := blockHash
tlog.Debug("getTxActions", "blockHash", blockHash, "blockNum", blockNum)
tlog.Debug("getTxActions", "height", height, "blockNum", blockNum) //根据blockHash,查询block,循环blockNum
for blockNum > 0 {
req := types.ReqHash{Hash: currHash}
req := &types.ReqBlocks{Start: height - blockNum + 1, End: height, IsDetail: false, Pid: []string{""}} tempBlock, err := ticket.GetAPI().GetBlockOverview(&req)
if err != nil {
return txActions, err
}
reqHashes.Hashes = append(reqHashes.Hashes, currHash)
currHash = tempBlock.Head.ParentHash
if tempBlock.Head.Height < 0 && blockNum > 1 {
return txActions, types.ErrBlockNotFound
}
blockNum--
}
blockDetails, err := ticket.GetAPI().GetBlocks(req) blockDetails, err := ticket.GetAPI().GetBlockByHashes(&reqHashes)
if err != nil { if err != nil {
tlog.Error("getTxActions", "height", height, "blockNum", blockNum, "err", err) tlog.Error("getTxActions", "blockHash", blockHash, "blockNum", blockNum, "err", err)
return txActions, err return txActions, err
} }
for _, block := range blockDetails.Items { for _, block := range blockDetails.Items {
//tlog.Debug("getTxActions", "blockHeight", block.Block.Height, "blockhash", block.Block.Hash()) tlog.Debug("getTxActions", "blockHeight", block.Block.Height, "blockhash", block.Block.Hash())
ticketAction, err := ticket.getMinerTx(block.Block) ticketAction, err := ticket.getMinerTx(block.Block)
if err != nil { if err != nil {
return txActions, err return txActions, err
......
...@@ -7,13 +7,13 @@ package commands ...@@ -7,13 +7,13 @@ package commands
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"math"
"os" "os"
"strconv" "strconv"
"strings" "strings"
"github.com/33cn/chain33/rpc/jsonclient" "github.com/33cn/chain33/rpc/jsonclient"
rpctypes "github.com/33cn/chain33/rpc/types" rpctypes "github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/system/dapp/commands"
"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"
"github.com/spf13/cobra" "github.com/spf13/cobra"
...@@ -72,31 +72,7 @@ func addCreateTokenTransferFlags(cmd *cobra.Command) { ...@@ -72,31 +72,7 @@ func addCreateTokenTransferFlags(cmd *cobra.Command) {
} }
func createTokenTransfer(cmd *cobra.Command, args []string) { func createTokenTransfer(cmd *cobra.Command, args []string) {
toAddr, _ := cmd.Flags().GetString("to") commands.CreateAssetTransfer(cmd, args, tokenty.TokenX)
amount, _ := cmd.Flags().GetFloat64("amount")
note, _ := cmd.Flags().GetString("note")
symbol, _ := cmd.Flags().GetString("symbol")
payload := &types.AssetsTransfer{
To: toAddr,
Amount: int64(math.Trunc((amount+0.0000001)*1e4)) * 1e4,
Note: []byte(note),
Cointoken: symbol,
}
data, err := json.Marshal(&payload)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
params := &rpctypes.CreateTxIn{
Execer: types.ExecName(tokenty.TokenX),
ActionName: "Transfer",
Payload: data,
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, nil)
ctx.RunWithoutMarshal()
} }
// CreateTokenTransferExecCmd create raw transfer tx // CreateTokenTransferExecCmd create raw transfer tx
...@@ -124,41 +100,7 @@ func addCreateTokenSendToExecFlags(cmd *cobra.Command) { ...@@ -124,41 +100,7 @@ func addCreateTokenSendToExecFlags(cmd *cobra.Command) {
} }
func createTokenSendToExec(cmd *cobra.Command, args []string) { func createTokenSendToExec(cmd *cobra.Command, args []string) {
paraName, _ := cmd.Flags().GetString("paraName") commands.CreateAssetSendToExec(cmd, args, tokenty.TokenX)
exec, _ := cmd.Flags().GetString("exec")
exec = getRealExecName(paraName, exec)
to, err := GetExecAddr(exec)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
amount, _ := cmd.Flags().GetFloat64("amount")
note, _ := cmd.Flags().GetString("note")
symbol, _ := cmd.Flags().GetString("symbol")
payload := &types.AssetsTransferToExec{
To: to,
Amount: int64(math.Trunc((amount+0.0000001)*1e4)) * 1e4,
Note: []byte(note),
Cointoken: symbol,
ExecName: exec,
}
data, err := json.Marshal(&payload)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
params := &rpctypes.CreateTxIn{
Execer: types.ExecName(tokenty.TokenX),
ActionName: "TransferToExec",
Payload: data,
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, nil)
ctx.RunWithoutMarshal()
} }
// CreateTokenWithdrawCmd create raw withdraw tx // CreateTokenWithdrawCmd create raw withdraw tx
...@@ -186,40 +128,7 @@ func addCreateTokenWithdrawFlags(cmd *cobra.Command) { ...@@ -186,40 +128,7 @@ func addCreateTokenWithdrawFlags(cmd *cobra.Command) {
} }
func createTokenWithdraw(cmd *cobra.Command, args []string) { func createTokenWithdraw(cmd *cobra.Command, args []string) {
exec, _ := cmd.Flags().GetString("exec") commands.CreateAssetWithdraw(cmd, args, tokenty.TokenX)
paraName, _ := cmd.Flags().GetString("paraName")
exec = getRealExecName(paraName, exec)
amount, _ := cmd.Flags().GetFloat64("amount")
note, _ := cmd.Flags().GetString("note")
symbol, _ := cmd.Flags().GetString("symbol")
exec = getRealExecName(paraName, exec)
execAddr, err := GetExecAddr(exec)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
payload := &types.AssetsWithdraw{
To: execAddr,
Amount: int64(math.Trunc((amount+0.0000001)*1e4)) * 1e4,
Note: []byte(note),
Cointoken: symbol,
ExecName: exec,
}
data, err := json.Marshal(&payload)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
params := &rpctypes.CreateTxIn{
Execer: types.ExecName(tokenty.TokenX),
ActionName: "Withdraw",
Payload: data,
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, nil)
ctx.RunWithoutMarshal()
} }
// GetTokensPreCreatedCmd get precreated tokens // GetTokensPreCreatedCmd get precreated tokens
......
...@@ -20,6 +20,11 @@ chain33背后故事: [chain33诞生记](https://mp.weixin.qq.com/s/9g5ZFDKJi9uzR ...@@ -20,6 +20,11 @@ chain33背后故事: [chain33诞生记](https://mp.weixin.qq.com/s/9g5ZFDKJi9uzR
视频教程: [视频教程](https://chain.33.cn/document/90) 视频教程: [视频教程](https://chain.33.cn/document/90)
# 感谢
[腾讯玄武实验室](https://github.com/33cn/chain33/issues?utf8=%E2%9C%93&q=label%3A%E8%85%BE%E8%AE%AF%E7%8E%84%E6%AD%A6%E5%AE%9E%E9%AA%8C%E5%AE%A4)
## Building from source ## Building from source
环境要求: Go (version 1.9 or later) 环境要求: Go (version 1.9 or later)
......
...@@ -276,8 +276,8 @@ func (acc *DB) loadAccountsHistory(api client.QueueProtocolAPI, addrs []string, ...@@ -276,8 +276,8 @@ func (acc *DB) loadAccountsHistory(api client.QueueProtocolAPI, addrs []string,
// GetBalance 获取某个状态下账户余额 // GetBalance 获取某个状态下账户余额
func (acc *DB) GetBalance(api client.QueueProtocolAPI, in *types.ReqBalance) ([]*types.Account, error) { func (acc *DB) GetBalance(api client.QueueProtocolAPI, in *types.ReqBalance) ([]*types.Account, error) {
switch in.GetExecer() { // load account
case types.ExecName("coins"): if in.AssetExec == in.Execer || "" == in.Execer {
addrs := in.GetAddresses() addrs := in.GetAddresses()
var exaddrs []string var exaddrs []string
for _, addr := range addrs { for _, addr := range addrs {
...@@ -306,34 +306,35 @@ func (acc *DB) GetBalance(api client.QueueProtocolAPI, in *types.ReqBalance) ([] ...@@ -306,34 +306,35 @@ func (acc *DB) GetBalance(api client.QueueProtocolAPI, in *types.ReqBalance) ([]
} }
} }
return accounts, nil return accounts, nil
default: }
execaddress := address.ExecAddress(in.GetExecer())
addrs := in.GetAddresses() // load exec account
var accounts []*types.Account execaddress := address.ExecAddress(in.GetExecer())
for _, addr := range addrs { addrs := in.GetAddresses()
var account *types.Account var accounts []*types.Account
var err error for _, addr := range addrs {
if len(in.StateHash) == 0 { var account *types.Account
account, err = acc.LoadExecAccountQueue(api, addr, execaddress) var err error
if err != nil { if len(in.StateHash) == 0 {
log.Error("GetBalance", "err", err.Error()) account, err = acc.LoadExecAccountQueue(api, addr, execaddress)
continue if err != nil {
} log.Error("GetBalance", "err", err.Error())
} else { continue
hash, err := common.FromHex(in.StateHash) }
if err != nil { } else {
return nil, err hash, err := common.FromHex(in.StateHash)
} if err != nil {
account, err = acc.LoadExecAccountHistoryQueue(api, addr, execaddress, hash) return nil, err
if err != nil { }
log.Error("GetBalance", "err", err.Error()) account, err = acc.LoadExecAccountHistoryQueue(api, addr, execaddress, hash)
continue if err != nil {
} log.Error("GetBalance", "err", err.Error())
continue
} }
accounts = append(accounts, account)
} }
return accounts, nil accounts = append(accounts, account)
} }
return accounts, nil
} }
// GetExecBalance 通过account模块获取地址账户在合约中的余额 // GetExecBalance 通过account模块获取地址账户在合约中的余额
......
...@@ -108,21 +108,24 @@ function start_chain33() { ...@@ -108,21 +108,24 @@ function start_chain33() {
echo "=========== #transfer to miner addr =============" echo "=========== #transfer to miner addr ============="
hash=$(${CLI} send coins transfer -a 10000 -n test -t 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944) hash=$(${CLI} send coins transfer -a 10000 -n test -t 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944)
echo "${hash}"
sleep ${chain33BlockTime} sleep ${chain33BlockTime}
txs=$(${CLI} tx query_hash -s "${hash}" | jq ".txs") result=$(${CLI} tx query -s "${hash}" | jq '.receipt.tyName')
if [ "${txs}" == "null" ]; then if [[ ${result} != '"ExecOk"' ]]; then
echo "transferTokenAdmin cannot find tx" echo "Failed"
${CLI} tx query -s "${hash}" | jq '.' | cat
exit 1 exit 1
fi fi
echo "=========== #transfer to token amdin =============" echo "=========== #transfer to token amdin ============="
hash=$(${CLI} send coins transfer -a 10 -n test -t 1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944) hash=$(${CLI} send coins transfer -a 10 -n test -t 1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944)
echo "${hash}"
sleep ${chain33BlockTime} sleep ${chain33BlockTime}
txs=$(${CLI} tx query_hash -s "${hash}" | jq ".txs") result=$(${CLI} tx query -s "${hash}" | jq '.receipt.tyName')
if [ "${txs}" == "null" ]; then if [[ ${result} != '"ExecOk"' ]]; then
echo "transferTokenAdmin cannot find tx" echo "Failed"
${CLI} tx query -s "${hash}" | jq '.' | cat
exit 1 exit 1
fi fi
...@@ -131,10 +134,12 @@ function start_chain33() { ...@@ -131,10 +134,12 @@ function start_chain33() {
signData=$(${CLI} wallet sign -d "${rawData}" -k 0xc34b5d9d44ac7b754806f761d3d4d2c4fe5214f6b074c19f069c4f5c2a29c8cc) signData=$(${CLI} wallet sign -d "${rawData}" -k 0xc34b5d9d44ac7b754806f761d3d4d2c4fe5214f6b074c19f069c4f5c2a29c8cc)
hash=$(${CLI} wallet send -d "${signData}") hash=$(${CLI} wallet send -d "${signData}")
echo "${hash}"
sleep ${chain33BlockTime} sleep ${chain33BlockTime}
txs=$(${CLI} tx query_hash -s "${hash}" | jq ".txs") result=$(${CLI} tx query -s "${hash}" | jq '.receipt.tyName')
if [ "${txs}" == "null" ]; then if [[ ${result} != '"ExecOk"' ]]; then
echo "transferTokenAdmin cannot find tx" echo "Failed"
${CLI} tx query -s "${hash}" | jq '.' | cat
exit 1 exit 1
fi fi
......
...@@ -121,21 +121,24 @@ function start_chain33() { ...@@ -121,21 +121,24 @@ function start_chain33() {
echo "=========== #transfer to miner addr =============" echo "=========== #transfer to miner addr ============="
hash=$(${CLI} send coins transfer -a 10000 -n test -t 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944) hash=$(${CLI} send coins transfer -a 10000 -n test -t 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944)
echo "${hash}"
sleep ${chain33BlockTime} sleep ${chain33BlockTime}
txs=$(${CLI} tx query_hash -s "${hash}" | jq ".txs") result=$(${CLI} tx query -s "${hash}" | jq '.receipt.tyName')
if [ "${txs}" == "null" ]; then if [[ ${result} != '"ExecOk"' ]]; then
echo "transferTokenAdmin cannot find tx" echo "Failed"
${CLI} tx query -s "${hash}" | jq '.' | cat
exit 1 exit 1
fi fi
echo "=========== #transfer to token amdin =============" echo "=========== #transfer to token amdin ============="
hash=$(${CLI} send coins transfer -a 10 -n test -t 1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944) hash=$(${CLI} send coins transfer -a 10 -n test -t 1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944)
echo "${hash}"
sleep ${chain33BlockTime} sleep ${chain33BlockTime}
txs=$(${CLI} tx query_hash -s "${hash}" | jq ".txs") result=$(${CLI} tx query -s "${hash}" | jq '.receipt.tyName')
if [ "${txs}" == "null" ]; then if [[ ${result} != '"ExecOk"' ]]; then
echo "transferTokenAdmin cannot find tx" echo "Failed"
${CLI} tx query -s "${hash}" | jq '.' | cat
exit 1 exit 1
fi fi
...@@ -144,10 +147,12 @@ function start_chain33() { ...@@ -144,10 +147,12 @@ function start_chain33() {
signData=$(${CLI} wallet sign -d "${rawData}" -k 0xc34b5d9d44ac7b754806f761d3d4d2c4fe5214f6b074c19f069c4f5c2a29c8cc) signData=$(${CLI} wallet sign -d "${rawData}" -k 0xc34b5d9d44ac7b754806f761d3d4d2c4fe5214f6b074c19f069c4f5c2a29c8cc)
hash=$(${CLI} wallet send -d "${signData}") hash=$(${CLI} wallet send -d "${signData}")
echo "${hash}"
sleep ${chain33BlockTime} sleep ${chain33BlockTime}
txs=$(${CLI} tx query_hash -s "${hash}" | jq ".txs") result=$(${CLI} tx query -s "${hash}" | jq '.receipt.tyName')
if [ "${txs}" == "null" ]; then if [[ ${result} != '"ExecOk"' ]]; then
echo "transferTokenAdmin cannot find tx" echo "Failed"
${CLI} tx query -s "${hash}" | jq '.' | cat
exit 1 exit 1
fi fi
......
...@@ -206,7 +206,20 @@ func (c *channelClient) GetAddrOverview(parm *types.ReqAddr) (*types.AddrOvervie ...@@ -206,7 +206,20 @@ func (c *channelClient) GetAddrOverview(parm *types.ReqAddr) (*types.AddrOvervie
// GetBalance get balance // GetBalance get balance
func (c *channelClient) GetBalance(in *types.ReqBalance) ([]*types.Account, error) { func (c *channelClient) GetBalance(in *types.ReqBalance) ([]*types.Account, error) {
return c.accountdb.GetBalance(c.QueueProtocolAPI, in) // in.AssetExec & in.AssetSymbol 新增参数,
// 不填时兼容原来的调用
if in.AssetExec == "" || in.AssetSymbol == "" {
in.AssetSymbol = "bty"
in.AssetExec = "coins"
return c.accountdb.GetBalance(c.QueueProtocolAPI, in)
}
acc, err := account.NewAccountDB(in.AssetExec, in.AssetSymbol, nil)
if err != nil {
log.Error("GetBalance", "Error", err.Error())
return nil, err
}
return acc.GetBalance(c.QueueProtocolAPI, in)
} }
// GetAllExecBalance get balance of exec // GetAllExecBalance get balance of exec
...@@ -288,3 +301,49 @@ func (c *channelClient) GetExecBalance(in *types.ReqGetExecBalance) (*types.Repl ...@@ -288,3 +301,49 @@ func (c *channelClient) GetExecBalance(in *types.ReqGetExecBalance) (*types.Repl
} }
return resp, nil return resp, nil
} }
// GetAssetBalance 通用的获得资产的接口
func (c *channelClient) GetAssetBalance(in *types.ReqBalance) ([]*types.Account, error) {
if in.AssetSymbol == "" || in.AssetExec == "" {
return nil, types.ErrInvalidParam
}
acc, err := account.NewAccountDB(in.AssetExec, in.AssetSymbol, nil)
if err != nil {
return nil, err
}
// load balance
if in.AssetExec == in.Execer || in.Execer == "" {
addrs := in.GetAddresses()
var queryAddrs []string
for _, addr := range addrs {
if err := address.CheckAddress(addr); err != nil {
addr = string(acc.AccountKey(addr))
}
queryAddrs = append(queryAddrs, addr)
}
accounts, err := acc.LoadAccounts(c.QueueProtocolAPI, queryAddrs)
if err != nil {
log.Error("GetAssetBalance", "err", err.Error(), "exec", in.AssetExec, "symbol", in.AssetSymbol,
"address", queryAddrs)
return nil, err
}
return accounts, nil
}
// load exec balance
execaddress := address.ExecAddress(in.GetExecer())
addrs := in.GetAddresses()
var accounts []*types.Account
for _, addr := range addrs {
acc, err := acc.LoadExecAccountQueue(c.QueueProtocolAPI, addr, execaddress)
if err != nil {
log.Error("GetAssetBalance for exector", "err", err.Error(), "exec", in.AssetExec,
"symbol", in.AssetSymbol, "address", addr, "where", in.Execer)
continue
}
accounts = append(accounts, acc)
}
return accounts, nil
}
...@@ -361,3 +361,66 @@ func TestChannelClient_GetBalance(t *testing.T) { ...@@ -361,3 +361,66 @@ func TestChannelClient_GetBalance(t *testing.T) {
// assert.NotNil(t, data) // assert.NotNil(t, data)
// assert.Nil(t, err) // assert.Nil(t, err)
// } // }
func testChannelClient_GetAssetBalanceCoin(t *testing.T) {
api := new(mocks.QueueProtocolAPI)
db := new(account.DB)
client := &channelClient{
QueueProtocolAPI: api,
accountdb: db,
}
head := &types.Header{StateHash: []byte("sdfadasds")}
api.On("GetLastHeader").Return(head, nil)
var acc = &types.Account{Addr: "1Jn2qu84Z1SUUosWjySggBS9pKWdAP3tZt", Balance: 100}
accv := types.Encode(acc)
storevalue := &types.StoreReplyValue{}
storevalue.Values = append(storevalue.Values, accv)
api.On("StoreGet", mock.Anything).Return(storevalue, nil)
var addrs = []string{"1Jn2qu84Z1SUUosWjySggBS9pKWdAP3tZt"}
var in = &types.ReqBalance{
AssetSymbol: "bty",
AssetExec: "coins",
Execer: "coins",
Addresses: addrs,
}
data, err := client.GetAssetBalance(in)
assert.Nil(t, err)
assert.Equal(t, acc.Addr, data[0].Addr)
}
func testChannelClient_GetAssetBalanceOther(t *testing.T) {
api := new(mocks.QueueProtocolAPI)
db := new(account.DB)
client := &channelClient{
QueueProtocolAPI: api,
accountdb: db,
}
head := &types.Header{StateHash: []byte("sdfadasds")}
api.On("GetLastHeader").Return(head, nil)
var acc = &types.Account{Addr: "1Jn2qu84Z1SUUosWjySggBS9pKWdAP3tZt", Balance: 100}
accv := types.Encode(acc)
storevalue := &types.StoreReplyValue{}
storevalue.Values = append(storevalue.Values, accv)
api.On("StoreGet", mock.Anything).Return(storevalue, nil)
var addrs = []string{"1Jn2qu84Z1SUUosWjySggBS9pKWdAP3tZt"}
var in = &types.ReqBalance{
AssetSymbol: "bty",
AssetExec: "coins",
Execer: types.ExecName("ticket"),
Addresses: addrs,
}
data, err := client.GetAssetBalance(in)
assert.Nil(t, err)
assert.Equal(t, acc.Addr, data[0].Addr)
}
func TestChannelClient_GetAssetBalance(t *testing.T) {
testChannelClient_GetAssetBalanceCoin(t)
testChannelClient_GetAssetBalanceOther(t)
}
...@@ -741,19 +741,12 @@ func (c *Chain33) GetWalletStatus(in types.ReqNil, result *interface{}) error { ...@@ -741,19 +741,12 @@ func (c *Chain33) GetWalletStatus(in types.ReqNil, result *interface{}) error {
// GetBalance get balance // GetBalance get balance
func (c *Chain33) GetBalance(in types.ReqBalance, result *interface{}) error { func (c *Chain33) GetBalance(in types.ReqBalance, result *interface{}) error {
balances, err := c.cli.GetBalance(&in) balances, err := c.cli.GetBalance(&in)
if err != nil { if err != nil {
return err return err
} }
var accounts []*rpctypes.Account
for _, balance := range balances { *result = fmtAccount(balances)
accounts = append(accounts, &rpctypes.Account{Addr: balance.GetAddr(),
Balance: balance.GetBalance(),
Currency: balance.GetCurrency(),
Frozen: balance.GetFrozen()})
}
*result = accounts
return nil return nil
} }
...@@ -1209,3 +1202,14 @@ func convertBlockDetails(details []*types.BlockDetail, retDetails *rpctypes.Bloc ...@@ -1209,3 +1202,14 @@ func convertBlockDetails(details []*types.BlockDetail, retDetails *rpctypes.Bloc
} }
return nil return nil
} }
func fmtAccount(balances []*types.Account) []*rpctypes.Account {
var accounts []*rpctypes.Account
for _, balance := range balances {
accounts = append(accounts, &rpctypes.Account{Addr: balance.GetAddr(),
Balance: balance.GetBalance(),
Currency: balance.GetCurrency(),
Frozen: balance.GetFrozen()})
}
return accounts
}
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"encoding/hex" "encoding/hex"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/client/mocks" "github.com/33cn/chain33/client/mocks"
"github.com/33cn/chain33/common" "github.com/33cn/chain33/common"
rpctypes "github.com/33cn/chain33/rpc/types" rpctypes "github.com/33cn/chain33/rpc/types"
...@@ -373,6 +374,7 @@ func newTestChain33(api *mocks.QueueProtocolAPI) *Chain33 { ...@@ -373,6 +374,7 @@ func newTestChain33(api *mocks.QueueProtocolAPI) *Chain33 {
return &Chain33{ return &Chain33{
cli: channelClient{ cli: channelClient{
QueueProtocolAPI: api, QueueProtocolAPI: api,
accountdb: account.NewCoinsAccount(),
}, },
} }
} }
...@@ -1290,3 +1292,58 @@ func TestChain33_GetExecBalance(t *testing.T) { ...@@ -1290,3 +1292,58 @@ func TestChain33_GetExecBalance(t *testing.T) {
err = client.GetExecBalance(in, &testResult2) err = client.GetExecBalance(in, &testResult2)
assert.NotNil(t, err) assert.NotNil(t, err)
} }
func TestChain33_GetBalance(t *testing.T) {
api := new(mocks.QueueProtocolAPI)
client := newTestChain33(api)
var addrs = []string{"1Jn2qu84Z1SUUosWjySggBS9pKWdAP3tZt"}
cases := []struct {
In types.ReqBalance
}{
{In: types.ReqBalance{
Execer: types.ExecName("coins"),
Addresses: addrs,
}},
{In: types.ReqBalance{
Execer: types.ExecName("ticket"),
Addresses: addrs,
}},
{In: types.ReqBalance{
AssetSymbol: "bty",
AssetExec: "coins",
Execer: types.ExecName("ticket"),
Addresses: addrs,
}},
{In: types.ReqBalance{
AssetSymbol: "bty",
AssetExec: "coins",
Execer: types.ExecName("coins"),
Addresses: addrs,
}},
}
for _, c := range cases {
c := c
t.Run("test GetBalance", func(t *testing.T) {
head := &types.Header{StateHash: []byte("sdfadasds")}
api.On("GetLastHeader").Return(head, nil)
var acc = &types.Account{Addr: "1Jn2qu84Z1SUUosWjySggBS9pKWdAP3tZt", Balance: 100}
accv := types.Encode(acc)
storevalue := &types.StoreReplyValue{}
storevalue.Values = append(storevalue.Values, accv)
api.On("StoreGet", mock.Anything).Return(storevalue, nil)
var data interface{}
err := client.GetBalance(c.In, &data)
assert.Nil(t, err)
result := data.([]*rpctypes.Account)
assert.Equal(t, 1, len(result))
//t.Error("result", "x", result)
assert.Equal(t, acc.Addr, result[0].Addr)
assert.Equal(t, int64(100), result[0].Balance)
})
}
}
// 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 commands
import (
"encoding/json"
"fmt"
"math"
"os"
"strings"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/rpc/jsonclient"
rpcTypes "github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/types"
"github.com/spf13/cobra"
)
// AssetCmd command
func AssetCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "asset",
Short: "Asset query",
Args: cobra.MinimumNArgs(1),
}
cmd.AddCommand(
GetAssetBalanceCmd(),
)
return cmd
}
// GetAssetBalanceCmd query asset balance
func GetAssetBalanceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "balance",
Short: "Query asset balance",
Run: assetBalance,
}
addAssetBalanceFlags(cmd)
return cmd
}
func addAssetBalanceFlags(cmd *cobra.Command) {
cmd.Flags().StringP("addr", "a", "", "account addr")
cmd.MarkFlagRequired("addr")
cmd.Flags().StringP("exec", "e", "", getExecuterNameString())
cmd.Flags().StringP("asset_exec", "", "coins", "the asset executor")
cmd.MarkFlagRequired("asset_exec")
cmd.Flags().StringP("asset_symbol", "", "bty", "the asset symbol")
cmd.MarkFlagRequired("asset_symbol")
cmd.Flags().IntP("height", "", -1, "block height")
}
func assetBalance(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
addr, _ := cmd.Flags().GetString("addr")
execer, _ := cmd.Flags().GetString("exec")
asset_symbol, _ := cmd.Flags().GetString("asset_symbol")
asset_exec, _ := cmd.Flags().GetString("asset_exec")
height, _ := cmd.Flags().GetInt("height")
err := address.CheckAddress(addr)
if err != nil {
if err = address.CheckMultiSignAddress(addr); err != nil {
fmt.Fprintln(os.Stderr, types.ErrInvalidAddress)
return
}
}
if execer == "" {
execer = asset_exec
}
if ok := types.IsAllowExecName([]byte(execer), []byte(execer)); !ok {
fmt.Fprintln(os.Stderr, types.ErrExecNameNotAllow)
return
}
stateHash := ""
if height >= 0 {
params := types.ReqBlocks{
Start: int64(height),
End: int64(height),
IsDetail: false,
}
var res rpcTypes.Headers
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.GetHeaders", params, &res)
_, err := ctx.RunResult()
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
h := res.Items[0]
stateHash = h.StateHash
}
var addrs []string
addrs = append(addrs, addr)
params := types.ReqBalance{
Addresses: addrs,
Execer: execer,
StateHash: stateHash,
AssetExec: asset_exec,
AssetSymbol: asset_symbol,
}
var res []*rpcTypes.Account
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.GetBalance", params, &res)
ctx.SetResultCb(parseGetBalanceRes)
ctx.Run()
}
// CreateAssetSendToExec 通用的创建 send_exec 交易, 额外指定资产合约
func CreateAssetSendToExec(cmd *cobra.Command, args []string, fromExec string) {
paraName, _ := cmd.Flags().GetString("paraName")
exec, _ := cmd.Flags().GetString("exec")
exec = getRealExecName(paraName, exec)
to, err := GetExecAddr(exec)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
amount, _ := cmd.Flags().GetFloat64("amount")
note, _ := cmd.Flags().GetString("note")
symbol, _ := cmd.Flags().GetString("symbol")
payload := &types.AssetsTransferToExec{
To: to,
Amount: int64(math.Trunc((amount+0.0000001)*1e4)) * 1e4,
Note: []byte(note),
Cointoken: symbol,
ExecName: exec,
}
data, err := json.Marshal(&payload)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
params := &rpcTypes.CreateTxIn{
Execer: types.ExecName(fromExec),
ActionName: "TransferToExec",
Payload: data,
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, nil)
ctx.RunWithoutMarshal()
}
// CreateAssetWithdraw 通用的创建 withdraw 交易, 额外指定资产合约
func CreateAssetWithdraw(cmd *cobra.Command, args []string, fromExec string) {
exec, _ := cmd.Flags().GetString("exec")
paraName, _ := cmd.Flags().GetString("paraName")
exec = getRealExecName(paraName, exec)
amount, _ := cmd.Flags().GetFloat64("amount")
note, _ := cmd.Flags().GetString("note")
symbol, _ := cmd.Flags().GetString("symbol")
exec = getRealExecName(paraName, exec)
execAddr, err := GetExecAddr(exec)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
payload := &types.AssetsWithdraw{
To: execAddr,
Amount: int64(math.Trunc((amount+0.0000001)*1e4)) * 1e4,
Note: []byte(note),
Cointoken: symbol,
ExecName: exec,
}
data, err := json.Marshal(&payload)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
params := &rpcTypes.CreateTxIn{
Execer: types.ExecName(fromExec),
ActionName: "Withdraw",
Payload: data,
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, nil)
ctx.RunWithoutMarshal()
}
// CreateAssetTransfer 通用的创建 transfer 交易, 额外指定资产合约
func CreateAssetTransfer(cmd *cobra.Command, args []string, fromExec string) {
toAddr, _ := cmd.Flags().GetString("to")
amount, _ := cmd.Flags().GetFloat64("amount")
note, _ := cmd.Flags().GetString("note")
symbol, _ := cmd.Flags().GetString("symbol")
payload := &types.AssetsTransfer{
To: toAddr,
Amount: int64(math.Trunc((amount+0.0000001)*1e4)) * 1e4,
Note: []byte(note),
Cointoken: symbol,
}
data, err := json.Marshal(&payload)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
params := &rpcTypes.CreateTxIn{
Execer: types.ExecName(fromExec),
ActionName: "Transfer",
Payload: data,
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, nil)
ctx.RunWithoutMarshal()
}
// GetExecAddr 获取执行器地址
func GetExecAddr(exec string) (string, error) {
if ok := types.IsAllowExecName([]byte(exec), []byte(exec)); !ok {
return "", types.ErrExecNameNotAllow
}
addrResult := address.ExecAddress(exec)
result := addrResult
return result, nil
}
func getRealExecName(paraName string, name string) string {
if strings.HasPrefix(name, "user.p.") {
return name
}
return paraName + name
}
...@@ -205,6 +205,8 @@ type ReqBalance struct { ...@@ -205,6 +205,8 @@ type ReqBalance struct {
//执行器名称 //执行器名称
Execer string `protobuf:"bytes,2,opt,name=execer,proto3" json:"execer,omitempty"` Execer string `protobuf:"bytes,2,opt,name=execer,proto3" json:"execer,omitempty"`
StateHash string `protobuf:"bytes,3,opt,name=stateHash,proto3" json:"stateHash,omitempty"` StateHash string `protobuf:"bytes,3,opt,name=stateHash,proto3" json:"stateHash,omitempty"`
AssetExec string `protobuf:"bytes,4,opt,name=asset_exec,json=assetExec,proto3" json:"asset_exec,omitempty"`
AssetSymbol string `protobuf:"bytes,5,opt,name=asset_symbol,json=assetSymbol,proto3" json:"asset_symbol,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -256,6 +258,20 @@ func (m *ReqBalance) GetStateHash() string { ...@@ -256,6 +258,20 @@ func (m *ReqBalance) GetStateHash() string {
return "" return ""
} }
func (m *ReqBalance) GetAssetExec() string {
if m != nil {
return m.AssetExec
}
return ""
}
func (m *ReqBalance) GetAssetSymbol() string {
if m != nil {
return m.AssetSymbol
}
return ""
}
// Account 的列表 // Account 的列表
type Accounts struct { type Accounts struct {
Acc []*Account `protobuf:"bytes,1,rep,name=acc,proto3" json:"acc,omitempty"` Acc []*Account `protobuf:"bytes,1,rep,name=acc,proto3" json:"acc,omitempty"`
...@@ -403,28 +419,30 @@ func init() { ...@@ -403,28 +419,30 @@ 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{
// 360 bytes of a gzipped FileDescriptorProto // 399 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x41, 0x4f, 0x32, 0x31, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0xc1, 0x8e, 0xd3, 0x30,
0x10, 0x4d, 0x59, 0x60, 0xd9, 0x21, 0x1f, 0x87, 0x1e, 0xc8, 0x86, 0x7c, 0xc6, 0xcd, 0x9e, 0xf6, 0x10, 0x95, 0x9b, 0x76, 0xb3, 0x99, 0xc2, 0x1e, 0x7c, 0x58, 0x59, 0x2b, 0x56, 0x84, 0x9c, 0x72,
0x60, 0x96, 0xc4, 0xf5, 0x0f, 0x40, 0x62, 0xe2, 0xcd, 0xa4, 0xf1, 0xc4, 0xc9, 0x52, 0x06, 0x21, 0x40, 0xa9, 0x44, 0xf8, 0x81, 0x56, 0x42, 0xe2, 0x86, 0x64, 0x38, 0xf5, 0x82, 0x1c, 0x77, 0x4a,
0x62, 0x77, 0x6d, 0x8b, 0x11, 0x7f, 0x80, 0xbf, 0xdb, 0xb4, 0x74, 0x61, 0x91, 0x68, 0xbc, 0xf5, 0x2b, 0xd2, 0x24, 0xd8, 0x2e, 0xa2, 0x7c, 0x00, 0x1f, 0xc2, 0x97, 0x22, 0x4f, 0x9d, 0x36, 0xa5,
0xcd, 0xeb, 0xbc, 0xf7, 0x66, 0x5a, 0xf8, 0xc7, 0x85, 0x28, 0xb7, 0xd2, 0xe4, 0x95, 0x2a, 0x4d, 0x02, 0xed, 0xad, 0xf3, 0xde, 0xcc, 0xbc, 0xe7, 0xd7, 0x09, 0x3c, 0x57, 0x5a, 0xb7, 0xfb, 0xc6,
0x49, 0x3b, 0x66, 0x57, 0xa1, 0x4e, 0x9f, 0x21, 0x9c, 0xec, 0xeb, 0x74, 0x04, 0x3d, 0xb1, 0x55, 0x15, 0x9d, 0x69, 0x5d, 0xcb, 0x27, 0xee, 0xd0, 0xa1, 0xcd, 0xbe, 0x42, 0x3c, 0x3f, 0xe2, 0xfc,
0x0a, 0xa5, 0xd8, 0xc5, 0x24, 0x21, 0x59, 0x87, 0x1d, 0x30, 0x8d, 0x21, 0x9c, 0xf3, 0x0d, 0x97, 0x01, 0x6e, 0xf5, 0xde, 0x18, 0x6c, 0xf4, 0x41, 0xb0, 0x94, 0xe5, 0x13, 0x79, 0xaa, 0xb9, 0x80,
0x02, 0xe3, 0x56, 0x42, 0xb2, 0x80, 0xd5, 0x90, 0x0e, 0xa1, 0xbb, 0x54, 0xe5, 0x07, 0xca, 0x38, 0xb8, 0x52, 0xb5, 0x6a, 0x34, 0x8a, 0x51, 0xca, 0xf2, 0x48, 0xf6, 0x25, 0xbf, 0x87, 0x9b, 0xb5,
0x70, 0x84, 0x47, 0x94, 0x42, 0x9b, 0x2f, 0x16, 0x2a, 0x6e, 0x27, 0x24, 0x8b, 0x98, 0x3b, 0xa7, 0x69, 0x7f, 0x62, 0x23, 0x22, 0x22, 0x42, 0xc5, 0x39, 0x8c, 0xd5, 0x6a, 0x65, 0xc4, 0x38, 0x65,
0x9f, 0x04, 0x46, 0x0c, 0x05, 0xae, 0x2b, 0x73, 0xfb, 0x8e, 0xc2, 0x1b, 0x3f, 0x28, 0x2e, 0xf5, 0x79, 0x22, 0xe9, 0x77, 0xf6, 0x8b, 0xc1, 0x83, 0x44, 0x8d, 0xdb, 0xce, 0xbd, 0xfb, 0x81, 0x3a,
0x12, 0x95, 0x0d, 0x80, 0xb6, 0x6c, 0xdb, 0x88, 0x6b, 0x3b, 0x60, 0x9a, 0x42, 0xbb, 0x52, 0xf8, 0x08, 0x7f, 0x32, 0xaa, 0xb1, 0x6b, 0x34, 0xde, 0x00, 0x7a, 0xd8, 0x8f, 0x31, 0x1a, 0x3b, 0xd5,
0xe6, 0xdc, 0xfb, 0xd7, 0x83, 0xdc, 0xa5, 0xcf, 0xbd, 0x02, 0x73, 0x1c, 0xcd, 0x20, 0xdc, 0x07, 0x3c, 0x83, 0x71, 0x67, 0xf0, 0x3b, 0xa9, 0x4f, 0xdf, 0xdc, 0x15, 0xe4, 0xbe, 0x08, 0x1b, 0x24,
0x36, 0x2e, 0xcb, 0xf9, 0xb5, 0x9a, 0x4e, 0x97, 0x30, 0xf4, 0x39, 0xbe, 0x67, 0xa8, 0x7d, 0xc8, 0x71, 0x3c, 0x87, 0xf8, 0x68, 0xd8, 0x91, 0x97, 0xeb, 0xb6, 0x9e, 0xce, 0xd6, 0x70, 0x1f, 0x7c,
0xdf, 0x7c, 0x5a, 0xbf, 0xfb, 0x3c, 0x02, 0x30, 0x7c, 0x9d, 0xfa, 0x55, 0xfd, 0x87, 0xc8, 0xae, 0xfc, 0xed, 0xa1, 0xd7, 0x61, 0x4f, 0xd3, 0x19, 0xfd, 0x5f, 0xe7, 0x37, 0x03, 0x90, 0xf8, 0x6d,
0x01, 0xb5, 0x46, 0x1d, 0x93, 0x24, 0xc8, 0x22, 0x76, 0x2c, 0xd8, 0x45, 0xda, 0x69, 0x51, 0x39, 0x11, 0xb2, 0x7a, 0x01, 0x89, 0xcf, 0x01, 0xad, 0x45, 0x2b, 0x58, 0x1a, 0xe5, 0x89, 0x3c, 0x03,
0xd1, 0x88, 0x79, 0x64, 0xbb, 0xb4, 0xe1, 0x06, 0xef, 0xb8, 0x5e, 0xb9, 0xb9, 0x22, 0x76, 0x2c, 0x3e, 0x49, 0xff, 0x5c, 0x34, 0xb4, 0x35, 0x91, 0xa1, 0xf2, 0x53, 0xd6, 0x29, 0x87, 0xef, 0x95,
0xa4, 0x57, 0xd0, 0xf3, 0xae, 0x9a, 0x26, 0x10, 0x70, 0x21, 0x9c, 0xf2, 0x79, 0x26, 0x4b, 0xa5, 0xdd, 0xd0, 0xc3, 0x12, 0x79, 0x06, 0xf8, 0x23, 0x80, 0xb2, 0x16, 0xdd, 0x67, 0xdf, 0x1d, 0xd2,
0xf7, 0xd0, 0x6f, 0x2c, 0xbe, 0x61, 0x49, 0x4e, 0x2c, 0x33, 0x08, 0xfd, 0x67, 0xf9, 0x69, 0x40, 0x4e, 0x08, 0xf1, 0x11, 0xf3, 0x57, 0xf0, 0xec, 0x48, 0xdb, 0xc3, 0xae, 0x6a, 0x6b, 0x31, 0xa1,
0x4f, 0xa7, 0x33, 0x18, 0x4c, 0x36, 0x1b, 0xab, 0x59, 0x0f, 0x59, 0xbf, 0x3b, 0x39, 0xbe, 0x3b, 0x86, 0x29, 0x61, 0x1f, 0x09, 0xca, 0x5e, 0xc3, 0x6d, 0x30, 0x6e, 0x79, 0x0a, 0x91, 0xd2, 0x9a,
0xbd, 0x39, 0xb1, 0x8d, 0x5b, 0x2e, 0x20, 0xf5, 0x9a, 0x0d, 0x86, 0x35, 0xaf, 0x4d, 0x2f, 0x67, 0xbc, 0x5d, 0x3f, 0xcb, 0x53, 0xd9, 0x07, 0x98, 0x0e, 0xfe, 0xbb, 0x81, 0x69, 0x76, 0x61, 0x3a,
0x17, 0x4f, 0x6b, 0xb3, 0xda, 0xce, 0x73, 0x51, 0xbe, 0x8c, 0x8b, 0x42, 0xc8, 0xb1, 0x58, 0xf1, 0x87, 0x38, 0xdc, 0xdb, 0xbf, 0x32, 0x0a, 0x74, 0xb6, 0x84, 0xbb, 0x79, 0x5d, 0xfb, 0x9d, 0x7d,
0xb5, 0x2c, 0x8a, 0xb1, 0xeb, 0x9c, 0x77, 0xdd, 0x4f, 0x2e, 0xbe, 0x02, 0x00, 0x00, 0xff, 0xff, 0x4c, 0xfd, 0xe9, 0xb0, 0xf3, 0xe9, 0xf0, 0xb7, 0x17, 0xb2, 0x62, 0x44, 0x06, 0x79, 0xd8, 0x39,
0x7b, 0xae, 0x1c, 0x1e, 0xda, 0x02, 0x00, 0x00, 0x60, 0xe4, 0xb0, 0x6d, 0xf1, 0x72, 0xf9, 0xf8, 0x65, 0xeb, 0x36, 0xfb, 0xaa, 0xd0, 0xed, 0x6e,
0x56, 0x96, 0xba, 0x99, 0xe9, 0x8d, 0xda, 0x36, 0x65, 0x39, 0xa3, 0xc9, 0xea, 0x86, 0x3e, 0x86,
0xf2, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb3, 0x61, 0x7c, 0x60, 0x1d, 0x03, 0x00, 0x00,
} }
...@@ -38,8 +38,10 @@ message ReqBalance { ...@@ -38,8 +38,10 @@ message ReqBalance {
//地址列表 //地址列表
repeated string addresses = 1; repeated string addresses = 1;
//执行器名称 //执行器名称
string execer = 2; string execer = 2;
string stateHash = 3; string stateHash = 3;
string asset_exec = 4;
string asset_symbol = 5;
} }
// Account 的列表 // Account 的列表
......
...@@ -60,6 +60,7 @@ func init() { ...@@ -60,6 +60,7 @@ func init() {
commands.VersionCmd(), commands.VersionCmd(),
sendCmd, sendCmd,
closeCmd, closeCmd,
commands.AssetCmd(),
) )
} }
......
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