From 15f4fbc0f13bc17662df6a6e320748338789ae89 Mon Sep 17 00:00:00 2001 From: Eunsoo Park Date: Fri, 8 Jan 2021 11:58:04 +0900 Subject: [PATCH] Fix QUERY message handling (#54) - check preCommit Data --- cmd/dbtest/cli.go | 13 ++++++++++-- cmd/dbtest/cli_query.go | 13 +++++++++--- cmd/sendipc/cli.go | 14 ++++++++++++- cmd/sendipc/cli_monitor.go | 2 +- cmd/sendipc/cli_query.go | 11 +++++----- core/db_claim.go | 35 ++++++++++++++++++++++++++++++++ core/msg.go | 38 ++++++++++++++++++++++++++--------- core/msg_test.go | 41 +++++++++++++++++++++++++++++--------- 8 files changed, 137 insertions(+), 30 deletions(-) diff --git a/cmd/dbtest/cli.go b/cmd/dbtest/cli.go index 7aa0dd2..75c9353 100644 --- a/cmd/dbtest/cli.go +++ b/cmd/dbtest/cli.go @@ -1,6 +1,7 @@ package main import ( + "encoding/hex" "flag" "fmt" "os" @@ -21,7 +22,9 @@ func (cli *CLI) printUsage() { fmt.Printf("\n [command]\n") fmt.Printf("\t create N NUM Create an Account DB with N Accout DBs and NUM accounts\n") fmt.Printf("\t delete Delete an Account DB\n") - fmt.Printf("\t query ADDRESS Query I-Score value with ADDRESS\n") + fmt.Printf("\t query ADDRESS [TXHash] Query I-Score value with ADDRESS\n") + fmt.Printf("\t ADDRESS Address to query\n") + fmt.Printf("\t TXHash Transaction hash in hex string to query.(Optional)\n") fmt.Printf("\t calculate TO BATCH Calculate I-Score of all account\n") fmt.Printf("\t TO Block height to calculate. Set 0 if you want current block+1\n") fmt.Printf("\t BATCH The number of DB write batch count\n") @@ -49,6 +52,7 @@ func (cli *CLI) Run() { createDBCount := createCmd.Int("db", 16, "The number of RC Account DB. (MAX:256)") createAccountCount := createCmd.Int("account", 10000, "The account number of RC Account DB") queryAddress := queryCmd.String("address", "", "Account address") + queryTXHash := queryCmd.String("txHash", "", "Transaction hash in hex string.(Optional)") calculateBlockHeight := calculateCmd.Uint64("block", 0, "Block height to calculate, Set 0 if you want current block +1") calculateWriteBatch := calculateCmd.Uint64("writebatch", 0, "The number of DB write batch count") @@ -113,7 +117,12 @@ func (cli *CLI) Run() { queryCmd.Usage() os.Exit(1) } - cli.query(dbName, *queryAddress) + txHash, err := hex.DecodeString(*queryTXHash) + if err != nil { + queryCmd.Usage() + os.Exit(1) + } + cli.query(dbName, *queryAddress, txHash) } if calculateCmd.Parsed() { diff --git a/cmd/dbtest/cli_query.go b/cmd/dbtest/cli_query.go index 1be7366..71af3cf 100644 --- a/cmd/dbtest/cli_query.go +++ b/cmd/dbtest/cli_query.go @@ -1,14 +1,16 @@ package main import ( + "encoding/hex" "fmt" "github.com/icon-project/rewardcalculator/common" "github.com/icon-project/rewardcalculator/core" "log" ) -func (cli *CLI) query(dbName string, key string) { - fmt.Printf("Query account. DB name: %s Address: %s\n", dbName, key) +func (cli *CLI) query(dbName string, key string, txHash []byte) { + fmt.Printf("Query account. DB name: %s Address: %s TXHash: %s\n", + dbName, key, hex.EncodeToString(txHash)) ctx, err := core.NewContext(DBDir, DBType, dbName, 0, "") if nil != err { @@ -16,7 +18,12 @@ func (cli *CLI) query(dbName string, key string) { return } - resp := core.DoQuery(ctx, *common.NewAddressFromString(key)) + req := &core.Query{ + Address: *common.NewAddressFromString(key), + TXHash: txHash, + } + + resp := core.DoQuery(ctx, req) fmt.Printf("Get value %s for %s\n", resp.IScore.String(), key) } diff --git a/cmd/sendipc/cli.go b/cmd/sendipc/cli.go index 6cd481a..e7e6a0a 100644 --- a/cmd/sendipc/cli.go +++ b/cmd/sendipc/cli.go @@ -1,6 +1,7 @@ package main import ( + "encoding/hex" "encoding/json" "flag" "fmt" @@ -61,6 +62,7 @@ func (cli *CLI) Run() { queryCmd := flag.NewFlagSet("query", flag.ExitOnError) queryAddress := queryCmd.String("address", "", "Account address") + queryTXHash := queryCmd.String("txHash", "", "Transaction hash in hex string.(Optional)") claimCmd := flag.NewFlagSet("claim", flag.ExitOnError) claimAddress := claimCmd.String("address", "", "Account address") @@ -249,8 +251,18 @@ func (cli *CLI) Run() { queryCmd.PrintDefaults() os.Exit(1) } + var txHash []byte + if *queryTXHash == "" { + txHash = nil + } else { + txHash, err = hex.DecodeString(*queryTXHash) + if err != nil { + queryCmd.Usage() + os.Exit(1) + } + } // send QUERY message - cli.query(conn, *queryAddress) + cli.query(conn, *queryAddress, txHash) } if calculateCmd.Parsed() { diff --git a/cmd/sendipc/cli_monitor.go b/cmd/sendipc/cli_monitor.go index abdc4bf..27d68a2 100644 --- a/cmd/sendipc/cli_monitor.go +++ b/cmd/sendipc/cli_monitor.go @@ -52,7 +52,7 @@ func (cli *CLI) readAndPush(conn ipc.Connection, targets []monitorTarget, url st for _, target := range targets { // read IScore from RC - resp := cli.query(conn, target.Address.String()) + resp := cli.query(conn, target.Address.String(), nil) target.IScore.Set(&resp.IScore.Int) // set metric diff --git a/cmd/sendipc/cli_query.go b/cmd/sendipc/cli_query.go index bbd9003..448b9dd 100644 --- a/cmd/sendipc/cli_query.go +++ b/cmd/sendipc/cli_query.go @@ -10,13 +10,14 @@ import ( -func (cli *CLI) query(conn ipc.Connection, address string) *core.ResponseQuery { - var addr common.Address +func (cli *CLI) query(conn ipc.Connection, address string, txHash []byte) *core.ResponseQuery { + req := &core.Query{ + Address: *common.NewAddressFromString(address), + TXHash: txHash, + } resp := new(core.ResponseQuery) - addr.SetString(address) - - conn.SendAndReceive(core.MsgQuery, cli.id, &addr, resp) + conn.SendAndReceive(core.MsgQuery, cli.id, req, resp) fmt.Printf("QUERY command get response: %s\n", resp.String()) return resp diff --git a/core/db_claim.go b/core/db_claim.go index 888d1a6..d51360e 100644 --- a/core/db_claim.go +++ b/core/db_claim.go @@ -1,6 +1,7 @@ package core import ( + "bytes" "encoding/hex" "fmt" "log" @@ -199,6 +200,10 @@ func (pc *PreCommit) SetBytes(bs []byte) error { return nil } +func (pc *PreCommit) IsEmpty() bool { + return pc.BlockHeight == 0 +} + func newPreCommit(blockHeight uint64, blockHash []byte, txIndex uint64, txHash []byte, address common.Address) *PreCommit { pc := new(PreCommit) @@ -343,6 +348,36 @@ func deletePreCommit(pcDB db.Database, start []byte, limit []byte) error { return nil } +func findPreCommit(pcDB db.Database, address common.Address, txHash []byte) (*PreCommit, error) { + bsSize := len(db.PrefixClaim) + bs := make([]byte, bsSize) + copy(bs, db.PrefixClaim) + prefix := util.BytesPrefix(bs) + + iter, err := pcDB.GetIterator() + if err != nil { + return nil, err + } + + // iterate & find + pc := new(PreCommit) + iter.New(prefix.Start, prefix.Limit) + for iter.Next() { + pc.SetBytes(iter.Value()) + if pc.Address.Equal(&address) && bytes.Compare(pc.TXHash, txHash) == 0 { + pc.SetID(iter.Key()) + break + } + } + iter.Release() + err = iter.Error() + if err != nil { + log.Printf("There is error while find preCommit. %v", err) + return nil, err + } + return pc, nil +} + func writePreCommitToClaimDB(preCommitDB db.Database, claimDB db.Database, claimBackupDB db.Database, blockHeight uint64, blockHash []byte) error { iter, err := preCommitDB.GetIterator() diff --git a/core/msg.go b/core/msg.go index e281977..dfdb897 100644 --- a/core/msg.go +++ b/core/msg.go @@ -181,6 +181,15 @@ func sendVersion(c ipc.Connection, msg uint, id uint32, blockHeight uint64, bloc return c.Send(msg, id, resp) } +type Query struct { + Address common.Address + TXHash []byte +} + +func (q *Query) String() string { + return fmt.Sprintf("Address: %s, TXHash: %s", q.Address.String(), hex.EncodeToString(q.TXHash[:])) +} + type ResponseQuery struct { Address common.Address IScore common.HexInt @@ -195,41 +204,52 @@ func (rq *ResponseQuery) String() string { } func (mh *msgHandler) query(c ipc.Connection, id uint32, data []byte) error { - var addr common.Address + var req Query mh.mgr.AddMsgTask() - if _, err := codec.MP.UnmarshalFromBytes(data, &addr); err != nil { + if _, err := codec.MP.UnmarshalFromBytes(data, &req); err != nil { return err } - log.Printf("\t QUERY request: address: %s", addr.String()) + log.Printf("\t QUERY request: %s", req.String()) - resp := DoQuery(mh.mgr.ctx, addr) + resp := DoQuery(mh.mgr.ctx, &req) mh.mgr.DoneMsgTask() log.Printf("Send message. (msg:%s, id:%d, data:%s)", MsgToString(MsgQuery), id, resp.String()) return c.Send(MsgQuery, id, &resp) } -func DoQuery(ctx *Context, addr common.Address) *ResponseQuery { +func DoQuery(ctx *Context, req *Query) *ResponseQuery { var claim *Claim = nil var ia *IScoreAccount = nil isDB := ctx.DB // make response var resp ResponseQuery - resp.Address = addr + resp.Address = req.Address + + // search from preCommit DB + if len(req.TXHash) != 0 { + pcDB := isDB.getPreCommitDB() + pc, _ := findPreCommit(pcDB, req.Address, req.TXHash) + if !pc.IsEmpty() { + resp.BlockHeight = pc.Data.BlockHeight + resp.IScore.SetInt64(0) + return &resp + } + } // read from claim DB cDB := isDB.getClaimDB() bucket, _ := cDB.GetBucket(db.PrefixIScore) - bs, _ := bucket.Get(addr.Bytes()) + bs, _ := bucket.Get(req.Address.Bytes()) if bs != nil { claim, _ = NewClaimFromBytes(bs) } // read from Query DB - qDB := isDB.getQueryDB(addr) + qDB := isDB.getQueryDB(req.Address) bucket, _ = qDB.GetBucket(db.PrefixIScore) - bs, _ = bucket.Get(addr.Bytes()) + bs, _ = bucket.Get(req.Address.Bytes()) if bs != nil { ia, _ = NewIScoreAccountFromBytes(bs) resp.BlockHeight = ia.BlockHeight diff --git a/core/msg_test.go b/core/msg_test.go index 538c665..e44be1c 100644 --- a/core/msg_test.go +++ b/core/msg_test.go @@ -1,6 +1,7 @@ package core import ( + "encoding/hex" "github.com/icon-project/rewardcalculator/common/db" "testing" @@ -13,9 +14,27 @@ func TestMsg_DoQuery(t *testing.T) { dbContent0 := IScoreAccount { Address: *address } dbContent0.BlockHeight = 100 dbContent0.IScore.SetUint64(claimMinIScore + 100) - - claim := ClaimMessage{BlockHeight: 101, BlockHash: []byte("1-1"), Address: *address} - commit := CommitClaim{Success:true, BlockHeight:claim.BlockHeight, BlockHash:claim.BlockHash, Address:claim.Address} + txHash := make([]byte, TXHashSize) + bs, _ := hex.DecodeString("abcd0123") + copy(txHash, bs) + + query := &Query{Address: *address} + queryWithTXHash := &Query{Address: *address, TXHash: txHash} + claim := ClaimMessage{ + BlockHeight: 101, + BlockHash: []byte("1-1"), + Address: *address, + TXIndex: 0, + TXHash: txHash, + } + commit := CommitClaim{ + Success:true, + BlockHeight:claim.BlockHeight, + BlockHash:claim.BlockHash, + Address:claim.Address, + TXIndex: 0, + TXHash: txHash, + } ctx := initTest(1) defer finalizeTest(ctx) @@ -26,7 +45,7 @@ func TestMsg_DoQuery(t *testing.T) { bucket.Set(dbContent0.ID(), dbContent0.Bytes()) // Query - resp := DoQuery(ctx, *address) + resp := DoQuery(ctx, query) assert.Equal(t, dbContent0.BlockHeight, resp.BlockHeight) assert.Equal(t, 0, dbContent0.IScore.Cmp(&resp.IScore.Int)) @@ -34,15 +53,20 @@ func TestMsg_DoQuery(t *testing.T) { DoClaim(ctx, &claim) // Query to claimed Account before commit - resp = DoQuery(ctx, *address) + resp = DoQuery(ctx, query) assert.Equal(t, dbContent0.BlockHeight, resp.BlockHeight) assert.Equal(t, 0, dbContent0.IScore.Cmp(&resp.IScore.Int)) + // Query with TX hash to claimed Account before commit + resp = DoQuery(ctx, queryWithTXHash) + assert.Equal(t, dbContent0.BlockHeight+1, resp.BlockHeight) + assert.Equal(t, int64(0), resp.IScore.Int64()) + // commit claim DoCommitClaim(ctx, &commit) // Query to claimed Account before commit to claim DB - resp = DoQuery(ctx, *address) + resp = DoQuery(ctx, query) assert.Equal(t, dbContent0.BlockHeight, resp.BlockHeight) assert.Equal(t, 0, dbContent0.IScore.Cmp(&resp.IScore.Int)) @@ -51,12 +75,11 @@ func TestMsg_DoQuery(t *testing.T) { claim.BlockHeight, claim.BlockHash) // Query to claimed Account after commit - resp = DoQuery(ctx, *address) + resp = DoQuery(ctx, query) assert.Equal(t, dbContent0.BlockHeight, resp.BlockHeight) - assert.Equal(t, 0, resp.IScore.Cmp(&common.NewHexIntFromUint64(100).Int)) + assert.Equal(t, int64(100), resp.IScore.Int64()) } - func TestMsg_DoInit(t *testing.T) { ctx := initTest(1) defer finalizeTest(ctx)