Commit aa055772 authored by kingwang's avatar kingwang Committed by 33cn

update chain33 08/12

parent 34c30c13
......@@ -24,24 +24,22 @@ import (
//var
var (
blockLastHeight = []byte("blockLastHeight")
bodyPrefix = []byte("Body:")
LastSequence = []byte("LastSequence")
headerPrefix = []byte("Header:")
heightToHeaderPrefix = []byte("HH:")
hashPrefix = []byte("Hash:")
tdPrefix = []byte("TD:")
heightToHashKeyPrefix = []byte("Height:")
seqToHashKey = []byte("Seq:")
HashToSeqPrefix = []byte("HashToSeq:")
seqCBPrefix = []byte("SCB:")
seqCBLastNumPrefix = []byte("SCBL:")
paraSeqToHashKey = []byte("ParaSeq:")
HashToParaSeqPrefix = []byte("HashToParaSeq:")
LastParaSequence = []byte("LastParaSequence")
storeLog = chainlog.New("submodule", "store")
AddBlock int64 = 1
DelBlock int64 = 2
blockLastHeight = []byte("blockLastHeight")
bodyPrefix = []byte("Body:")
LastSequence = []byte("LastSequence")
headerPrefix = []byte("Header:")
heightToHeaderPrefix = []byte("HH:")
hashPrefix = []byte("Hash:")
tdPrefix = []byte("TD:")
heightToHashKeyPrefix = []byte("Height:")
seqToHashKey = []byte("Seq:")
HashToSeqPrefix = []byte("HashToSeq:")
seqCBPrefix = []byte("SCB:")
seqCBLastNumPrefix = []byte("SCBL:")
paraSeqToHashKey = []byte("ParaSeq:")
HashToParaSeqPrefix = []byte("HashToParaSeq:")
LastParaSequence = []byte("LastParaSequence")
storeLog = chainlog.New("submodule", "store")
)
//GetLocalDBKeyList 获取本地键值列表
......@@ -590,7 +588,7 @@ func (bs *BlockStore) SaveBlock(storeBatch dbm.Batch, blockdetail *types.BlockDe
if bs.saveSequence || bs.isParaChain {
//存储记录block序列执行的type add
lastSequence, err = bs.saveBlockSequence(storeBatch, hash, height, AddBlock, sequence)
lastSequence, err = bs.saveBlockSequence(storeBatch, hash, height, types.AddBlock, sequence)
if err != nil {
storeLog.Error("SaveBlock SaveBlockSequence", "height", height, "hash", common.ToHex(hash), "error", err)
return lastSequence, err
......@@ -619,7 +617,7 @@ func (bs *BlockStore) DelBlock(storeBatch dbm.Batch, blockdetail *types.BlockDet
if bs.saveSequence || bs.isParaChain {
//存储记录block序列执行的type del
lastSequence, err := bs.saveBlockSequence(storeBatch, hash, height, DelBlock, sequence)
lastSequence, err := bs.saveBlockSequence(storeBatch, hash, height, types.DelBlock, sequence)
if err != nil {
storeLog.Error("DelBlock SaveBlockSequence", "height", height, "hash", common.ToHex(hash), "error", err)
return lastSequence, err
......@@ -1029,7 +1027,7 @@ func (bs *BlockStore) saveBlockSequence(storeBatch dbm.Batch, hash []byte, heigh
sequenceBytes := types.Encode(&types.Int64{Data: newSequence})
// hash->seq 只记录add block时的hash和seq对应关系
if Type == AddBlock {
if Type == types.AddBlock {
storeBatch.Set(calcHashToSequenceKey(hash, bs.isParaChain), sequenceBytes)
}
......@@ -1054,7 +1052,7 @@ func (bs *BlockStore) saveBlockSequence(storeBatch dbm.Batch, hash []byte, heigh
// hash->seq 只记录add block时的hash和seq对应关系
sequenceBytes := types.Encode(&types.Int64{Data: mainSeq})
if Type == AddBlock {
if Type == types.AddBlock {
storeBatch.Set(calcHashToMainSequenceKey(hash), sequenceBytes)
}
storeBatch.Set(LastSequence, sequenceBytes)
......@@ -1301,7 +1299,7 @@ func (bs *BlockStore) CreateSequences(batchSize int64) {
// seq->hash
var blockSequence types.BlockSequence
blockSequence.Hash = header.Hash
blockSequence.Type = AddBlock
blockSequence.Type = types.AddBlock
BlockSequenceByte, err := proto.Marshal(&blockSequence)
if err != nil {
storeLog.Error("CreateSequences Marshal BlockSequence", "height", i, "hash", common.ToHex(header.Hash), "error", err)
......
......@@ -601,7 +601,7 @@ func testGetBlockSequences(t *testing.T, chain *blockchain.BlockChain) {
Sequences, err := chain.GetBlockSequences(&reqBlock)
if err == nil && Sequences != nil {
for _, sequence := range Sequences.Items {
if sequence.Type != blockchain.AddBlock {
if sequence.Type != types.AddBlock {
t.Error("testGetBlockSequences sequence type check error")
}
}
......
......@@ -23,22 +23,29 @@ func (chain *BlockChain) GetParaTxByTitle(seq *types.ReqParaTxByTitle) (*types.P
return nil, err
}
//获取区块的seq信息
req := &types.ReqBlocks{Start: seq.Start, End: seq.End, IsDetail: false, Pid: []string{}}
sequences, err := chain.GetBlockSequences(req)
if err != nil {
filterlog.Error("GetParaTxByTitle:GetBlockSequences", "err", err.Error())
return nil, err
//对获取区块的起始和结束值做校验,最多一次取1000个区块,防止取的数据过大导致内存异常
if seq.End > seq.Start && (seq.End-seq.Start > types.MaxBlockCountPerTime) {
seq.End = seq.Start + types.MaxBlockCountPerTime - 1
}
//通过区块hash获取区块信息
var reqHashes types.ReqHashes
for _, item := range sequences.Items {
if item != nil {
reqHashes.Hashes = append(reqHashes.Hashes, item.GetHash())
var sequences *types.BlockSequences
if seq.IsSeq {
req := &types.ReqBlocks{Start: seq.Start, End: seq.End, IsDetail: false, Pid: []string{}}
sequences, err = chain.GetBlockSequences(req)
if err != nil {
filterlog.Error("GetParaTxByTitle:GetBlockSequences", "err", err.Error())
return nil, err
}
for _, item := range sequences.Items {
if item != nil {
reqHashes.Hashes = append(reqHashes.Hashes, item.GetHash())
}
}
} else {
reqHashes = chain.getBlockHashes(seq.Start, seq.End)
}
//通过区块hash获取区块信息
blocks, err := chain.GetBlockByHashes(reqHashes.Hashes)
if err != nil {
filterlog.Error("GetParaTxByTitle:GetBlockByHashes", "err", err)
......@@ -51,7 +58,11 @@ func (chain *BlockChain) GetParaTxByTitle(seq *types.ReqParaTxByTitle) (*types.P
for i, block := range blocks.Items {
if block != nil {
paraTx = block.FilterParaTxsByTitle(seq.Title)
paraTx.Type = sequences.Items[i].GetType()
if seq.IsSeq {
paraTx.Type = sequences.Items[i].GetType()
} else {
paraTx.Type = types.AddBlock
}
} else {
paraTx = nil
}
......@@ -60,13 +71,24 @@ func (chain *BlockChain) GetParaTxByTitle(seq *types.ReqParaTxByTitle) (*types.P
return &paraTxs, err
}
//checkInputParam 入参检测,主要检测seq的end的值已经title是否合法
func (chain *BlockChain) checkInputParam(seq *types.ReqParaTxByTitle) error {
//checkInputParam 入参检测,主要检测req的end的值以及title是否合法
func (chain *BlockChain) checkInputParam(req *types.ReqParaTxByTitle) error {
var err error
var lastblock int64
//入参数校验
blockLastSeq, err := chain.blockStore.LoadBlockLastSequence()
if err != nil || seq.End > blockLastSeq || blockLastSeq < 0 || !strings.HasPrefix(seq.Title, types.ParaKeyX) {
filterlog.Error("checkInputParam", "blockLastSeq", blockLastSeq, "seq", seq, "err", err)
if req.GetStart() > req.GetEnd() {
chainlog.Error("checkInputParam input must Start <= End:", "Start", req.Start, "End", req.End)
return types.ErrEndLessThanStartHeight
}
//需要区分是通过seq/height来获取平行链交易
if req.IsSeq {
lastblock, err = chain.blockStore.LoadBlockLastSequence()
} else {
lastblock = chain.GetBlockHeight()
}
if err != nil || req.End > lastblock || lastblock < 0 || !strings.HasPrefix(req.Title, types.ParaKeyX) {
filterlog.Error("checkInputParam", "lastblock", lastblock, "req", req, "err", err)
return types.ErrInvalidParam
}
return nil
......
......@@ -142,17 +142,36 @@ func TestGetParaTxByTitle(t *testing.T) {
time.Sleep(sendTxWait)
}
var req types.ReqParaTxByTitle
//通过seq获取para交易
req.Start = 0
req.End = curheight
req.Title = "user.p.hyb."
testgetParaTxByTitle(t, blockchain, &req, false, false, nil)
req.IsSeq = true
testgetParaTxByTitle(t, blockchain, &req, 0)
//通过height获取para交易
req.IsSeq = false
testgetParaTxByTitle(t, blockchain, &req, 0)
//通过height获取para交易
req.IsSeq = false
req.End = curheight + 1
testgetParaTxByTitle(t, blockchain, &req, 1)
chainlog.Info("TestGetParaTxByTitle end --------------------")
}
func testgetParaTxByTitle(t *testing.T, blockchain *blockchain.BlockChain, req *types.ReqParaTxByTitle, isGroup bool, haveMainTx bool, hashs []string) {
func testgetParaTxByTitle(t *testing.T, blockchain *blockchain.BlockChain, req *types.ReqParaTxByTitle, flag int) {
count := req.End - req.Start + 1
ParaTxDetails, err := blockchain.GetParaTxByTitle(req)
require.NoError(t, err)
if flag == 0 {
require.NoError(t, err)
}
if flag == 1 {
assert.Equal(t, err, types.ErrInvalidParam)
return
}
itemsLen := len(ParaTxDetails.Items)
assert.Equal(t, count, int64(itemsLen))
for i, txDetail := range ParaTxDetails.Items {
if txDetail != nil {
......
......@@ -481,6 +481,14 @@ func (chain *BlockChain) delParaChainBlockDetail(msg *queue.Message) {
func (chain *BlockChain) addParaChainBlockDetail(msg *queue.Message) {
parablockDetail := msg.Data.(*types.ParaChainBlockDetail)
//根据配置chain.cfgBatchSync和parablockDetail.IsSync
//来决定写数据库时是否需要刷盘,主要是为了同步阶段提高执行区块的效率
if !parablockDetail.IsSync && !chain.cfgBatchSync {
atomic.CompareAndSwapInt32(&chain.isbatchsync, 1, 0)
} else {
atomic.CompareAndSwapInt32(&chain.isbatchsync, 0, 1)
}
chainlog.Debug("EventAddParaChainBlockDetail", "height", parablockDetail.Blockdetail.Block.Height, "hash", common.HashHex(parablockDetail.Blockdetail.Block.Hash()))
// 平行链上P2P模块关闭,不用广播区块
blockDetail, err := chain.ProcAddParaChainBlockMsg(false, parablockDetail, "self")
......
......@@ -10,11 +10,18 @@ import (
)
//GetBlockByHashes 通过blockhash 获取对应的block信息
//从数据库获取区块不能太多,防止内存异常。一次最多获取100M区块数据从数据库
func (chain *BlockChain) GetBlockByHashes(hashes [][]byte) (respblocks *types.BlockDetails, err error) {
var blocks types.BlockDetails
size := 0
for _, hash := range hashes {
block, err := chain.LoadBlockByHash(hash)
if err == nil && block != nil {
size += block.Size()
if size > types.MaxBlockSizePerTime {
chainlog.Error("GetBlockByHashes:overflow", "MaxBlockSizePerTime", types.MaxBlockSizePerTime)
return &blocks, nil
}
blocks.Items = append(blocks.Items, block)
} else {
blocks.Items = append(blocks.Items, nil)
......@@ -264,3 +271,18 @@ func (chain *BlockChain) ProcAddBlockMsg(broadcast bool, blockdetail *types.Bloc
chainlog.Debug("ProcAddBlockMsg result:", "height", blockdetail.Block.Height, "ismain", ismain, "isorphan", isorphan, "hash", common.ToHex(blockdetail.Block.Hash()), "err", err)
return blockdetail, err
}
//getBlockHashes 获取指定height区间对应的blockhashes
func (chain *BlockChain) getBlockHashes(startheight, endheight int64) types.ReqHashes {
var reqHashes types.ReqHashes
for i := startheight; i <= endheight; i++ {
hash, err := chain.blockStore.GetBlockHashByHeight(i)
if hash == nil || err != nil {
storeLog.Error("getBlockHashesByHeight", "height", i, "error", err)
reqHashes.Hashes = append(reqHashes.Hashes, nil)
} else {
reqHashes.Hashes = append(reqHashes.Hashes, hash)
}
}
return reqHashes
}
......@@ -50,6 +50,16 @@ func (chain *BlockChain) Rollback() {
if err != nil {
panic(fmt.Sprintln("rollback LoadBlockByHeight err :", err))
}
if chain.cfg.RollbackSave { //本地保存临时区块
lastHeightSave := false
if i == startHeight {
lastHeightSave = true
}
err = chain.WriteBlockToDbTemp(blockdetail.Block, lastHeightSave)
if err != nil {
panic(fmt.Sprintln("rollback WriteBlockToDbTemp fail", "height", blockdetail.Block.Height, "error ", err))
}
}
sequence := int64(-1)
if chain.isParaChain {
// 获取平行链的seq
......@@ -64,17 +74,6 @@ func (chain *BlockChain) Rollback() {
}
// 删除storedb中的状态高度
chain.sendDelStore(blockdetail.Block.StateHash, blockdetail.Block.Height)
// 删除之后,本地保存临时区块
if chain.cfg.RollbackSave {
lastHeightSave := false
if i == startHeight {
lastHeightSave = true
}
err = chain.WriteBlockToDbTemp(blockdetail.Block, lastHeightSave)
if err != nil {
panic(fmt.Sprintln("rollback WriteBlockToDbTemp fail", "height", blockdetail.Block.Height, "error ", err))
}
}
chainlog.Info("chain rollback ", "height: ", i, "blockheight", blockdetail.Block.Height, "hash", common.ToHex(blockdetail.Block.Hash()), "state hash", common.ToHex(blockdetail.Block.StateHash))
}
}
......
......@@ -5,9 +5,12 @@
package blockchain
import (
"fmt"
"math/rand"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestTask(t *testing.T) {
......@@ -69,27 +72,18 @@ func TestTaskTimeOut(t *testing.T) {
t.Log("task not start")
return
}
defer task.Cancel()
timeoutHeight := make(chan int64, 1)
timeoutcb := func(height int64) {
timeOutProc(height)
fmt.Println("timeout:height", height)
timeoutHeight <- height
}
task.Start(1, 10, nil, timeoutcb)
task.Start(1, 11, nil, timeoutcb)
perm := rand.Perm(10)
for i := 0; i < len(perm); i++ {
time.Sleep(time.Millisecond * 10)
task.Done(int64(perm[i]) + 1)
if i < len(perm)-1 && !task.InProgress() {
task.Cancel()
t.Log("task not done, but InProgress is false")
return
}
if i == len(perm)-1 && task.InProgress() {
task.Cancel()
t.Log("task is done, but InProgress is true")
return
}
}
}
func timeOutProc(height int64) {
chainlog.Info("timeOutProc", "height", height)
h := <-timeoutHeight
assert.Equal(t, h, int64(11))
}
......@@ -5,6 +5,7 @@
package commands
import (
"bytes"
"encoding/json"
"fmt"
"os"
......@@ -27,15 +28,16 @@ func StatCmd() *cobra.Command {
}
cmd.AddCommand(
GetTotalCoinsCmd(),
GetExecBalanceCmd(),
getTotalCoinsCmd(),
getExecBalanceCmd(),
totalFeeCmd(),
)
return cmd
}
// GetTotalCoinsCmd get total coins
func GetTotalCoinsCmd() *cobra.Command {
// getTotalCoinsCmd get total coins
func getTotalCoinsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "total_coins",
Short: "Get total amount of a token (default: bty of current height)",
......@@ -57,43 +59,32 @@ func totalCoins(cmd *cobra.Command, args []string) {
height, _ := cmd.Flags().GetInt64("height")
actual, _ := cmd.Flags().GetString("actual")
if height == -1 {
rpc, err := jsonclient.NewJSONClient(rpcAddr)
rpc, err := jsonclient.NewJSONClient(rpcAddr)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
var stateHashHex string
if height < 0 {
header, err := getLastBlock(rpc)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
var res rpctypes.Header
err = rpc.Call("Chain33.GetLastHeader", nil, &res)
height = header.Height
stateHashHex = header.StateHash
} else {
blocks, err := getBlocks(height, height, rpc)
if err != nil {
fmt.Fprintln(os.Stderr, err)
fmt.Fprintf(os.Stderr, "GetBlocksErr:%s", err.Error())
return
}
height = res.Height
stateHashHex = blocks.Items[0].Block.StateHash
}
// 获取高度statehash
params := rpctypes.BlockParam{
Start: height,
End: height,
//Isdetail: false,
Isdetail: true,
}
rpc, err := jsonclient.NewJSONClient(rpcAddr)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
var res rpctypes.BlockDetails
err = rpc.Call("Chain33.GetBlocks", params, &res)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
stateHash, err := common.FromHex(res.Items[0].Block.StateHash)
stateHash, err := common.FromHex(stateHashHex)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
......@@ -104,32 +95,14 @@ func totalCoins(cmd *cobra.Command, args []string) {
resp := commandtypes.GetTotalCoinsResult{}
if symbol == "bty" {
//查询高度blockhash
params := types.ReqInt{Height: height}
var res1 rpctypes.ReplyHash
err = rpc.Call("Chain33.GetBlockHash", params, &res1)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
blockHash, err := common.FromHex(res1.Hash)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
//查询手续费
key := append([]byte("TotalFeeKey:"), blockHash...)
params2 := types.LocalDBGet{Keys: [][]byte{key}}
var res2 types.TotalFee
err = rpc.Call("Chain33.QueryTotalFee", params2, &res2)
//查询历史总手续费
fee, err := queryTotalFeeWithHeight(height, rpc)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
resp.TxCount = res2.TxCount
resp.TxCount = fee.TxCount
var issueCoins int64
//只适用bty主网计算
if height < 2270000 {
......@@ -137,7 +110,7 @@ func totalCoins(cmd *cobra.Command, args []string) {
} else { //挖矿产量降低30->8
issueCoins = 22*2269999 + height*8
}
totalAmount = (317430000+issueCoins)*types.Coin - res2.Fee
totalAmount = (317430000+issueCoins)*types.Coin - fee.Fee
resp.TotalAmount = strconv.FormatFloat(float64(totalAmount)/float64(types.Coin), 'f', 4, 64)
} else {
var req types.ReqString
......@@ -210,8 +183,8 @@ func totalCoins(cmd *cobra.Command, args []string) {
fmt.Println(string(data))
}
// GetExecBalanceCmd get exec-addr balance of specific addr
func GetExecBalanceCmd() *cobra.Command {
// getExecBalanceCmd get exec-addr balance of specific addr
func getExecBalanceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "exec_balance",
Short: "Get the exec amount of a token of one address (default: all exec-addr bty of current height of one addr)",
......@@ -238,43 +211,30 @@ func execBalance(cmd *cobra.Command, args []string) {
execAddr, _ := cmd.Flags().GetString("exec_addr")
height, _ := cmd.Flags().GetInt64("height")
if height == -1 {
rpc, err := jsonclient.NewJSONClient(rpcAddr)
rpc, err := jsonclient.NewJSONClient(rpcAddr)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
var stateHashHex string
if height < 0 {
header, err := getLastBlock(rpc)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
var res rpctypes.Header
err = rpc.Call("Chain33.GetLastHeader", nil, &res)
stateHashHex = header.StateHash
} else {
blocks, err := getBlocks(height, height, rpc)
if err != nil {
fmt.Fprintln(os.Stderr, err)
fmt.Fprintf(os.Stderr, "GetBlocksErr:%s", err.Error())
return
}
height = res.Height
}
// 获取高度statehash
params := rpctypes.BlockParam{
Start: height,
End: height,
//Isdetail: false,
Isdetail: true,
stateHashHex = blocks.Items[0].Block.StateHash
}
rpc, err := jsonclient.NewJSONClient(rpcAddr)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
var res rpctypes.BlockDetails
err = rpc.Call("Chain33.GetBlocks", params, &res)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
stateHash, err := common.FromHex(res.Items[0].Block.StateHash)
stateHash, err := common.FromHex(stateHashHex)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
......@@ -293,7 +253,6 @@ func execBalance(cmd *cobra.Command, args []string) {
ExecAddr: []byte(execAddr),
Execer: exec,
}
reqParam.StateHash = stateHash
if len(execAddr) > 0 {
reqParam.Count = 1 //由于精确匹配一条记录,所以这里设定为1
......@@ -366,3 +325,152 @@ func convertReplyToResult(reply *types.ReplyGetExecBalance, result *commandtypes
result.ExecBalances = append(result.ExecBalances, item)
}
}
// totalFeeCmd query total fee command
func totalFeeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "total_fee",
Short: "query total transaction fee, support specific block height interval [start, end]",
Run: totalFee,
}
cmd.Flags().Int64P("start_height", "s", 0, "start block height, default 0")
cmd.Flags().Int64P("end_height", "e", -1, "end block height, default current block height")
return cmd
}
func totalFee(cmd *cobra.Command, args []string) {
rpcAddr, _ := cmd.Flags().GetString("rpc_laddr")
start, _ := cmd.Flags().GetInt64("start_height")
end, _ := cmd.Flags().GetInt64("end_height")
var startFeeAmount, endFeeAmount int64
rpc, err := jsonclient.NewJSONClient(rpcAddr)
if err != nil {
fmt.Fprintf(os.Stderr, "NewJsonClientErr:%s\n", err.Error())
return
}
if start < 0 {
start = 0
}
if start > 0 {
totalFee, err := queryTotalFeeWithHeight(start-1, rpc)
if err != nil {
fmt.Fprintf(os.Stderr, "QueryStartFeeErr:%s\n", err.Error())
return
}
startFeeAmount = totalFee.Fee
}
if end < 0 {
//last block fee
currentHeight, totalFee, err := queryCurrentTotalFee(rpc)
if err != nil {
fmt.Fprintf(os.Stderr, "QueryCurrentTotalFeeErr:%s\n", err.Error())
return
}
endFeeAmount = totalFee.Fee
end = currentHeight
} else {
totalFee, err := queryTotalFeeWithHeight(end, rpc)
if err != nil {
fmt.Fprintf(os.Stderr, "QueryEndFeeErr:%s\n", err.Error())
return
}
endFeeAmount = totalFee.Fee
}
fee := endFeeAmount - startFeeAmount
if fee < 0 {
fee = 0
}
resp := fmt.Sprintf(`{"startHeight":%d,"endHeight":%d, "totalFee":%s}`, start, end, commandtypes.FormatAmountValue2Display(fee))
buf := &bytes.Buffer{}
err = json.Indent(buf, []byte(resp), "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "JsonIndentResultErr:%s\n", err.Error())
return
}
fmt.Println(buf.String())
}
//get last block header
func getLastBlock(rpc *jsonclient.JSONClient) (*rpctypes.Header, error) {
res := &rpctypes.Header{}
err := rpc.Call("Chain33.GetLastHeader", nil, &res)
if err != nil {
return nil, err
}
return res, nil
}
//get block hash with height
func getBlockHash(height int64, rpc *jsonclient.JSONClient) (string, error) {
params := types.ReqInt{Height: height}
var res rpctypes.ReplyHash
err := rpc.Call("Chain33.GetBlockHash", params, &res)
if err != nil {
return "", err
}
return res.Hash, nil
}
func queryCurrentTotalFee(rpc *jsonclient.JSONClient) (int64, *types.TotalFee, error) {
header, err := getLastBlock(rpc)
if err != nil {
return 0, nil, err
}
fee, err := queryTotalFeeWithHash(header.Hash, rpc)
if err != nil {
return 0, nil, err
}
return header.Height, fee, nil
}
func queryTotalFeeWithHeight(height int64, rpc *jsonclient.JSONClient) (*types.TotalFee, error) {
hash, err := getBlockHash(height, rpc)
if err != nil {
return nil, err
}
fee, err := queryTotalFeeWithHash(hash, rpc)
if err != nil {
return nil, err
}
return fee, nil
}
func queryTotalFeeWithHash(blockHash string, rpc *jsonclient.JSONClient) (*types.TotalFee, error) {
hash, err := common.FromHex(blockHash)
if err != nil {
return nil, err
}
//查询手续费
params := types.LocalDBGet{Keys: [][]byte{hash[:]}}
res := &types.TotalFee{}
err = rpc.Call("Chain33.QueryTotalFee", params, &res)
if err != nil {
return nil, err
}
return res, nil
}
func getBlocks(start, end int64, rpc *jsonclient.JSONClient) (*rpctypes.BlockDetails, error) {
// 获取blocks
params := rpctypes.BlockParam{
Start: start,
End: end,
//Isdetail: false,
Isdetail: true,
}
res := &rpctypes.BlockDetails{}
err := rpc.Call("Chain33.GetBlocks", params, &res)
if err != nil {
return nil, err
}
return res, nil
}
......@@ -171,14 +171,14 @@ func addWalletListTxsFlags(cmd *cobra.Command) {
cmd.Flags().Int32P("count", "c", 0, "number of transactions")
cmd.MarkFlagRequired("count")
cmd.Flags().Int32P("direction", "d", 1, "query direction (0: pre page, 1: next page)")
cmd.Flags().Int32P("direction", "d", 0, "query direction (0: pre page, 1: next page)")
}
func walletListTxs(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
txHash, _ := cmd.Flags().GetString("from")
count, _ := cmd.Flags().GetInt32("count")
direction, _ := cmd.Flags().GetInt32("dir")
direction, _ := cmd.Flags().GetInt32("direction")
params := rpctypes.ReqWalletTransactionList{
FromTx: txHash,
Count: count,
......
......@@ -116,6 +116,9 @@ func NewTree(db dbm.DB, sync bool) *Tree {
// 使能情况下非空创建当前整tree的缓存
if enableMemTree && memTree == nil {
memTree = NewTreeMap(50 * 10000)
if tkCloseCacheLen == 0 {
tkCloseCacheLen = 10 * 10000
}
tkCloseCache = NewTreeARC(int(tkCloseCacheLen))
}
return &Tree{
......
......@@ -244,3 +244,8 @@ func (blockDetail *BlockDetail) filterParaTxGroup(tx *Transaction, index int) ([
}
return txDetails, endIdx
}
// Size 获取blockDetail的Size
func (blockDetail *BlockDetail) Size() int {
return Size(blockDetail)
}
......@@ -61,7 +61,10 @@ const (
Float1E4 float64 = 10000.0
AirDropMinIndex uint32 = 100000000 //通过钱包的seed生成一个空投地址,最小index索引
AirDropMaxIndex uint32 = 101000000 //通过钱包的seed生成一个空投地址,最大index索引
MaxBlockCountPerTime int64 = 1000 //从数据库中一次性获取block的最大数 1000个
MaxBlockSizePerTime = 100000000 //从数据库中一次性获取block的最大size100M
AddBlock int64 = 1
DelBlock int64 = 2
)
//全局账户私钥/公钥
......
......@@ -203,9 +203,11 @@ message BlockSequences {
//平行链区块详细信息
// blockdetail : 区块详细信息
// sequence :区块序列号
// isSync:写数据库时是否需要刷盘
message ParaChainBlockDetail {
BlockDetail blockdetail = 1;
int64 sequence = 2;
bool isSync = 3;
}
// 定义para交易结构
......@@ -239,4 +241,5 @@ message ReqParaTxByTitle {
int64 start = 1;
int64 end = 2;
string title = 3;
bool isSeq = 4;
}
......@@ -202,10 +202,16 @@ func (store *Store) GetTxDetailByIter(TxList *types.ReqWalletTransactionList) (*
}
var txbytes [][]byte
//FromTx是空字符串时。默认从最新的交易开始取count个
//FromTx是空字符串时,
//Direction == 0从最新的交易开始倒序取count个
//Direction == 1从最早的交易开始正序取count个
if len(TxList.FromTx) == 0 {
list := store.NewListHelper()
txbytes = list.IteratorScanFromLast(CalcTxKey(""), TxList.Count)
if TxList.Direction == 0 {
txbytes = list.IteratorScanFromLast(CalcTxKey(""), TxList.Count)
} else {
txbytes = list.IteratorScanFromFirst(CalcTxKey(""), TxList.Count)
}
if len(txbytes) == 0 {
storelog.Error("GetTxDetailByIter IteratorScanFromLast does not exist tx!")
return nil, types.ErrTxNotExist
......
......@@ -415,9 +415,11 @@ func testProcImportPrivKey(t *testing.T, wallet *Wallet) {
func testProcWalletTxList(t *testing.T, wallet *Wallet) {
println("TestProcWalletTxList begin")
//倒序获取最新的三笔交易
txList := &types.ReqWalletTransactionList{
Count: 3,
Direction: 1,
Direction: 0,
FromTx: []byte(""),
}
msg := wallet.client.NewMessage("wallet", types.EventWalletTransactionList, txList)
......@@ -427,14 +429,26 @@ func testProcWalletTxList(t *testing.T, wallet *Wallet) {
walletTxDetails := resp.GetData().(*types.WalletTxDetails)
var FromTxstr string
index := make([]int64, 3)
if len(walletTxDetails.TxDetails) != 3 {
t.Error("testProcWalletTxList failed")
}
println("TestProcWalletTxList dir last-------")
for _, walletTxDetail := range walletTxDetails.TxDetails {
for i, walletTxDetail := range walletTxDetails.TxDetails {
println("TestProcWalletTxList", "Direction", txList.Direction, "WalletTxDetail", walletTxDetail.String())
index[i] = walletTxDetail.GetHeight()*100000 + walletTxDetail.GetIndex()
FromTxstr = fmt.Sprintf("%018d", walletTxDetail.GetHeight()*100000+walletTxDetail.GetIndex())
}
//倒序index值的判断,index[0]>index[1]>index[2]
if index[0] <= index[1] {
println("TestProcWalletTxList", "index[0]", index[0], "index[1]", index[1])
t.Error("testProcWalletTxList:Reverse check fail!")
}
if index[1] <= index[2] {
println("TestProcWalletTxList", "index[1]", index[1], "index[2]", index[2])
t.Error("testProcWalletTxList:Reverse check fail!")
}
txList.Direction = 1
txList.Count = 2
......@@ -466,6 +480,34 @@ func testProcWalletTxList(t *testing.T, wallet *Wallet) {
for _, walletTxDetail := range walletTxDetails.TxDetails {
println("TestProcWalletTxList", "Direction", txList.Direction, "WalletTxDetail", walletTxDetail.String())
}
//正序获取最早的三笔交易
txList = &types.ReqWalletTransactionList{
Count: 3,
Direction: 1,
FromTx: []byte(""),
}
msg = wallet.client.NewMessage("wallet", types.EventWalletTransactionList, txList)
wallet.client.Send(msg, true)
resp, err = wallet.client.Wait(msg)
require.NoError(t, err)
walletTxDetails = resp.GetData().(*types.WalletTxDetails)
if len(walletTxDetails.TxDetails) != 3 {
t.Error("testProcWalletTxList failed")
}
for i, walletTxDetail := range walletTxDetails.TxDetails {
index[i] = walletTxDetail.GetHeight()*100000 + walletTxDetail.GetIndex()
}
//正序index值的判断,index[0]<index[1]<index[2]
if index[0] >= index[1] {
println("TestProcWalletTxList", "index[0]", index[0], "index[1]", index[1])
t.Error("testProcWalletTxList:positive check fail!")
}
if index[1] >= index[2] {
println("TestProcWalletTxList", "index[1]", index[1], "index[2]", index[2])
t.Error("testProcWalletTxList:positive check fail!")
}
println("TestProcWalletTxList end")
println("--------------------------")
}
......
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