Commit c5d585c4 authored by 陈德海's avatar 陈德海

mempool add get proper fee

parent 9d75053f
...@@ -73,7 +73,7 @@ poolCacheSize=10240 ...@@ -73,7 +73,7 @@ poolCacheSize=10240
[mempool.sub.score] [mempool.sub.score]
poolCacheSize=10240 poolCacheSize=10240
timeParam=1 #时间占价格比例 timeParam=1 #时间占价格比例
priceConstant=1544 #手续费相对于时间的一个合适的常量,取当前unxi时间戳前四位数,排序时手续费高1e-5~=快1s priceConstant=3 #手续费相对于时间的一个的常量,排队时手续费高1e3的分数~=快1h的分数
pricePower=1 #常量比例 pricePower=1 #常量比例
[mempool.sub.price] [mempool.sub.price]
......
...@@ -130,3 +130,23 @@ func (cache *Queue) Walk(count int, cb func(value *mempool.Item) bool) { ...@@ -130,3 +130,23 @@ func (cache *Queue) Walk(count int, cb func(value *mempool.Item) bool) {
return i != count return i != count
}) })
} }
// GetProperFee 获取合适的手续费,取前100的平均价格
func (cache *Queue) GetProperFee() int64 {
var sumFee int64
var properFee int64
if cache.Size() == 0 {
return cache.subConfig.ProperFee
}
i := 0
cache.Walk(0, func(tx *mempool.Item) bool {
if i == 100 {
return false
}
sumFee += tx.Value.Fee
i++
return true
})
properFee = sumFee / int64(i)
return properFee
}
...@@ -113,9 +113,9 @@ func TestTimeCompetition(t *testing.T) { ...@@ -113,9 +113,9 @@ func TestTimeCompetition(t *testing.T) {
func TestPriceCompetition(t *testing.T) { func TestPriceCompetition(t *testing.T) {
cache := initEnv(1) cache := initEnv(1)
cache.Push(item1) cache.Push(item3)
cache.Push(item4) cache.Push(item4)
assert.Equal(t, false, cache.Exist(string(item1.Value.Hash()))) assert.Equal(t, false, cache.Exist(string(item3.Value.Hash())))
assert.Equal(t, true, cache.Exist(string(item4.Value.Hash()))) assert.Equal(t, true, cache.Exist(string(item4.Value.Hash())))
} }
...@@ -149,3 +149,13 @@ func TestQueueDirection(t *testing.T) { ...@@ -149,3 +149,13 @@ func TestQueueDirection(t *testing.T) {
assert.Equal(t, 5, i) assert.Equal(t, 5, i)
assert.Equal(t, true, lastScore == cache.txList.GetIterator().Last().Score) assert.Equal(t, true, lastScore == cache.txList.GetIterator().Last().Score)
} }
func TestGetProperFee(t *testing.T) {
cache := initEnv(0)
assert.Equal(t, cache.subConfig.ProperFee, cache.GetProperFee())
cache.Push(item1)
cache.Push(item4)
cache.GetProperFee()
assert.Equal(t, (item1.Value.Fee+item4.Value.Fee)/2, cache.GetProperFee())
}
...@@ -75,7 +75,7 @@ poolCacheSize=10240 ...@@ -75,7 +75,7 @@ poolCacheSize=10240
[mempool.sub.score] [mempool.sub.score]
poolCacheSize=10240 poolCacheSize=10240
timeParam=1 #时间占价格比例 timeParam=1 #时间占价格比例
priceConstant=1544 #手续费相对于时间的一个合适的常量,取当前unxi时间戳前四位数,排序时手续费高1e-5~=快1s priceConstant=3 #手续费相对于时间的一个的常量,排队时手续费高1e3的分数~=快1h的分数
pricePower=1 #常量比例 pricePower=1 #常量比例
[mempool.sub.price] [mempool.sub.price]
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
type subConfig struct { type subConfig struct {
PoolCacheSize int64 `json:"poolCacheSize"` PoolCacheSize int64 `json:"poolCacheSize"`
ProperFee int64 `json:"properFee"`
} }
func init() { func init() {
...@@ -25,6 +26,9 @@ func New(cfg *types.Mempool, sub []byte) queue.Module { ...@@ -25,6 +26,9 @@ func New(cfg *types.Mempool, sub []byte) queue.Module {
if subcfg.PoolCacheSize == 0 { if subcfg.PoolCacheSize == 0 {
subcfg.PoolCacheSize = cfg.PoolCacheSize subcfg.PoolCacheSize = cfg.PoolCacheSize
} }
if subcfg.ProperFee == 0 {
subcfg.ProperFee = cfg.MinTxFee
}
c.SetQueueCache(NewQueue(subcfg)) c.SetQueueCache(NewQueue(subcfg))
return c return c
} }
...@@ -3,6 +3,7 @@ package score ...@@ -3,6 +3,7 @@ package score
import ( import (
"bytes" "bytes"
"encoding/gob" "encoding/gob"
"time"
"github.com/33cn/chain33/common/skiplist" "github.com/33cn/chain33/common/skiplist"
"github.com/33cn/chain33/system/mempool" "github.com/33cn/chain33/system/mempool"
...@@ -36,7 +37,8 @@ func (cache *Queue) newSkipValue(item *mempool.Item) (*skiplist.SkipValue, error ...@@ -36,7 +37,8 @@ func (cache *Queue) newSkipValue(item *mempool.Item) (*skiplist.SkipValue, error
return nil, err return nil, err
} }
size := len(buf.Bytes()) size := len(buf.Bytes())
return &skiplist.SkipValue{Score: cache.subConfig.PriceConstant*(item.Value.Fee/int64(size))*cache.subConfig.PricePower - cache.subConfig.TimeParam*item.EnterTime, Value: item}, nil return &skiplist.SkipValue{Score: cache.subConfig.PriceConstant*(item.Value.Fee/int64(size))*
cache.subConfig.PricePower - cache.subConfig.TimeParam*item.EnterTime, Value: item}, nil
} }
// Exist 是否存在 // Exist 是否存在
...@@ -122,3 +124,26 @@ func (cache *Queue) Walk(count int, cb func(value *mempool.Item) bool) { ...@@ -122,3 +124,26 @@ func (cache *Queue) Walk(count int, cb func(value *mempool.Item) bool) {
return i != count return i != count
}) })
} }
// GetProperFee 获取合适的手续费
func (cache *Queue) GetProperFee() int64 {
var sumScore int64
var properFee int64
if cache.Size() == 0 {
return cache.subConfig.ProperFee
}
i := 0
cache.Walk(0, func(tx *mempool.Item) bool {
if i == 100 {
return false
}
//这里的int64(500)是一般交易的大小
sumScore += cache.subConfig.PriceConstant*tx.Value.Fee*
cache.subConfig.PricePower*int64(500) - cache.subConfig.TimeParam*tx.EnterTime
i++
return true
})
properFee = (sumScore/int64(cache.Size()) + cache.subConfig.TimeParam*time.Now().Unix()) /
(cache.subConfig.PriceConstant * cache.subConfig.PricePower * int64(500))
return properFee
}
package score package score
import ( import (
"testing"
"github.com/33cn/chain33/common" "github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address" "github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/crypto" "github.com/33cn/chain33/common/crypto"
...@@ -10,6 +8,8 @@ import ( ...@@ -10,6 +8,8 @@ import (
drivers "github.com/33cn/chain33/system/mempool" drivers "github.com/33cn/chain33/system/mempool"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"testing"
"time"
) )
var ( var (
...@@ -21,11 +21,11 @@ var ( ...@@ -21,11 +21,11 @@ var (
amount = int64(1e8) amount = int64(1e8)
v = &cty.CoinsAction_Transfer{Transfer: &types.AssetsTransfer{Amount: amount}} v = &cty.CoinsAction_Transfer{Transfer: &types.AssetsTransfer{Amount: amount}}
transfer = &cty.CoinsAction{Value: v, Ty: cty.CoinsActionTransfer} transfer = &cty.CoinsAction{Value: v, Ty: cty.CoinsActionTransfer}
tx1 = &types.Transaction{Execer: []byte("coins"), Payload: types.Encode(transfer), Fee: 1000000, Expire: 1, To: toAddr} tx1 = &types.Transaction{Execer: []byte("coins"), Payload: types.Encode(transfer), Fee: 100000, Expire: 1, To: toAddr}
tx2 = &types.Transaction{Execer: []byte("coins"), Payload: types.Encode(transfer), Fee: 1000000, Expire: 2, To: toAddr} tx2 = &types.Transaction{Execer: []byte("coins"), Payload: types.Encode(transfer), Fee: 100000, Expire: 2, To: toAddr}
tx3 = &types.Transaction{Execer: []byte("coins"), Payload: types.Encode(transfer), Fee: 1000000, Expire: 3, To: toAddr} tx3 = &types.Transaction{Execer: []byte("coins"), Payload: types.Encode(transfer), Fee: 100000, Expire: 3, To: toAddr}
tx4 = &types.Transaction{Execer: []byte("coins"), Payload: types.Encode(transfer), Fee: 2000000, Expire: 4, To: toAddr} tx4 = &types.Transaction{Execer: []byte("coins"), Payload: types.Encode(transfer), Fee: 200000, Expire: 4, To: toAddr}
tx5 = &types.Transaction{Execer: []byte("coins"), Payload: types.Encode(transfer), Fee: 1000000, Expire: 5, To: toAddr} tx5 = &types.Transaction{Execer: []byte("coins"), Payload: types.Encode(transfer), Fee: 100000, Expire: 5, To: toAddr}
item1 = &drivers.Item{Value: tx1, Priority: tx1.Fee, EnterTime: types.Now().Unix()} item1 = &drivers.Item{Value: tx1, Priority: tx1.Fee, EnterTime: types.Now().Unix()}
item2 = &drivers.Item{Value: tx2, Priority: tx2.Fee, EnterTime: types.Now().Unix()} item2 = &drivers.Item{Value: tx2, Priority: tx2.Fee, EnterTime: types.Now().Unix()}
item3 = &drivers.Item{Value: tx3, Priority: tx3.Fee, EnterTime: types.Now().Unix() - 1000} item3 = &drivers.Item{Value: tx3, Priority: tx3.Fee, EnterTime: types.Now().Unix() - 1000}
...@@ -113,9 +113,9 @@ func TestTimeCompetition(t *testing.T) { ...@@ -113,9 +113,9 @@ func TestTimeCompetition(t *testing.T) {
func TestPriceCompetition(t *testing.T) { func TestPriceCompetition(t *testing.T) {
cache := initEnv(1) cache := initEnv(1)
cache.Push(item1) cache.Push(item3)
cache.Push(item4) cache.Push(item4)
assert.Equal(t, false, cache.Exist(string(item1.Value.Hash()))) assert.Equal(t, false, cache.Exist(string(item3.Value.Hash())))
assert.Equal(t, true, cache.Exist(string(item4.Value.Hash()))) assert.Equal(t, true, cache.Exist(string(item4.Value.Hash())))
} }
...@@ -149,3 +149,19 @@ func TestQueueDirection(t *testing.T) { ...@@ -149,3 +149,19 @@ func TestQueueDirection(t *testing.T) {
assert.Equal(t, 5, i) assert.Equal(t, 5, i)
assert.Equal(t, true, lastScore == cache.txList.GetIterator().Last().Score) assert.Equal(t, true, lastScore == cache.txList.GetIterator().Last().Score)
} }
func TestGetProperFee(t *testing.T) {
cache := initEnv(0)
assert.Equal(t, cache.subConfig.ProperFee, cache.GetProperFee())
cache.Push(item3)
cache.Push(item4)
cache.GetProperFee()
score3 := item3.Priority*cache.subConfig.PriceConstant*cache.subConfig.PricePower*int64(500) -
item3.EnterTime*cache.subConfig.TimeParam
score4 := item4.Priority*cache.subConfig.PriceConstant*cache.subConfig.PricePower*int64(500) -
item4.EnterTime*cache.subConfig.TimeParam
properFee := ((score3+score4)/2 + time.Now().Unix()*cache.subConfig.TimeParam) /
(cache.subConfig.PriceConstant * cache.subConfig.PricePower * int64(500))
assert.Equal(t, properFee, cache.GetProperFee())
}
...@@ -75,7 +75,7 @@ poolCacheSize=10240 ...@@ -75,7 +75,7 @@ poolCacheSize=10240
[mempool.sub.score] [mempool.sub.score]
poolCacheSize=10240 poolCacheSize=10240
timeParam=1 #时间占价格比例 timeParam=1 #时间占价格比例
priceConstant=1544 #手续费相对于时间的一个合适的常量,取当前unxi时间戳前四位数,排队时手续费高1e-5的分数~=快1s的分数 priceConstant=3 #手续费相对于时间的一个的常量,排队时手续费高1e3的分数~=快1h的分数
pricePower=1 #常量比例 pricePower=1 #常量比例
[mempool.sub.price] [mempool.sub.price]
......
...@@ -14,6 +14,7 @@ type subConfig struct { ...@@ -14,6 +14,7 @@ type subConfig struct {
TimeParam int64 `json:"timeParam"` TimeParam int64 `json:"timeParam"`
PriceConstant int64 `json:"priceConstant"` PriceConstant int64 `json:"priceConstant"`
PricePower int64 `json:"pricePower"` PricePower int64 `json:"pricePower"`
ProperFee int64 `json:"properFee"`
} }
func init() { func init() {
...@@ -28,6 +29,9 @@ func New(cfg *types.Mempool, sub []byte) queue.Module { ...@@ -28,6 +29,9 @@ func New(cfg *types.Mempool, sub []byte) queue.Module {
if subcfg.PoolCacheSize == 0 { if subcfg.PoolCacheSize == 0 {
subcfg.PoolCacheSize = cfg.PoolCacheSize subcfg.PoolCacheSize = cfg.PoolCacheSize
} }
if subcfg.ProperFee == 0 {
subcfg.ProperFee = cfg.MinTxFee
}
c.SetQueueCache(NewQueue(subcfg)) c.SetQueueCache(NewQueue(subcfg))
return c return c
} }
...@@ -47,6 +47,8 @@ func (m *mockMempool) SetQueueClient(q queue.Queue) { ...@@ -47,6 +47,8 @@ func (m *mockMempool) SetQueueClient(q queue.Queue) {
msg.Reply(client.NewMessage(mempoolKey, types.EventReplyTxList, &types.ReplyTxList{})) msg.Reply(client.NewMessage(mempoolKey, types.EventReplyTxList, &types.ReplyTxList{}))
case types.EventGetLastMempool: case types.EventGetLastMempool:
msg.Reply(client.NewMessage(mempoolKey, types.EventReplyTxList, &types.ReplyTxList{})) msg.Reply(client.NewMessage(mempoolKey, types.EventReplyTxList, &types.ReplyTxList{}))
case types.EventGetProperFee:
msg.Reply(client.NewMessage(mempoolKey, types.EventReplyProperFee, &types.ReplyProperFee{}))
default: default:
msg.ReplyErr("Do not support", types.ErrNotSupport) msg.ReplyErr("Do not support", types.ErrNotSupport)
} }
......
...@@ -453,6 +453,29 @@ func (_m *QueueProtocolAPI) GetMempool() (*types.ReplyTxList, error) { ...@@ -453,6 +453,29 @@ func (_m *QueueProtocolAPI) GetMempool() (*types.ReplyTxList, error) {
return r0, r1 return r0, r1
} }
// GetProperFee provides a mock function with given fields:
func (_m *QueueProtocolAPI) GetProperFee() (*types.ReplyProperFee, error) {
ret := _m.Called()
var r0 *types.ReplyProperFee
if rf, ok := ret.Get(0).(func() *types.ReplyProperFee); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*types.ReplyProperFee)
}
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetNetInfo provides a mock function with given fields: // GetNetInfo provides a mock function with given fields:
func (_m *QueueProtocolAPI) GetNetInfo() (*types.NodeNetInfo, error) { func (_m *QueueProtocolAPI) GetNetInfo() (*types.NodeNetInfo, error) {
ret := _m.Called() ret := _m.Called()
......
...@@ -468,6 +468,19 @@ func (q *QueueProtocol) GetLastMempool() (*types.ReplyTxList, error) { ...@@ -468,6 +468,19 @@ func (q *QueueProtocol) GetLastMempool() (*types.ReplyTxList, error) {
return nil, types.ErrTypeAsset return nil, types.ErrTypeAsset
} }
// GetProperFee get proper fee from mempool
func (q *QueueProtocol) GetProperFee() (*types.ReplyProperFee, error) {
msg, err := q.query(mempoolKey, types.EventGetProperFee, &types.ReqNil{})
if err != nil {
log.Error("GetProperFee", "Error", err.Error())
return nil, err
}
if reply, ok := msg.GetData().(*types.ReplyProperFee); ok {
return reply, nil
}
return nil, types.ErrTypeAsset
}
// GetBlockOverview get block head detil by hash // GetBlockOverview get block head detil by hash
func (q *QueueProtocol) GetBlockOverview(param *types.ReqHash) (*types.BlockOverview, error) { func (q *QueueProtocol) GetBlockOverview(param *types.ReqHash) (*types.BlockOverview, error) {
if param == nil { if param == nil {
......
...@@ -79,6 +79,7 @@ func TestQueueProtocol(t *testing.T) { ...@@ -79,6 +79,7 @@ func TestQueueProtocol(t *testing.T) {
testPeerInfo(t, api) testPeerInfo(t, api)
testGetHeaders(t, api) testGetHeaders(t, api)
testGetLastMempool(t, api) testGetLastMempool(t, api)
testGetProperFee(t, api)
testGetBlockOverview(t, api) testGetBlockOverview(t, api)
testGetAddrOverview(t, api) testGetAddrOverview(t, api)
testGetBlockHash(t, api) testGetBlockHash(t, api)
...@@ -341,6 +342,13 @@ func testGetLastMempool(t *testing.T, api client.QueueProtocolAPI) { ...@@ -341,6 +342,13 @@ func testGetLastMempool(t *testing.T, api client.QueueProtocolAPI) {
} }
} }
func testGetProperFee(t *testing.T, api client.QueueProtocolAPI) {
_, err := api.GetProperFee()
if err != nil {
t.Error("Call GetProperFee Failed.", err)
}
}
func testGetHeaders(t *testing.T, api client.QueueProtocolAPI) { func testGetHeaders(t *testing.T, api client.QueueProtocolAPI) {
_, err := api.GetHeaders(&types.ReqBlocks{}) _, err := api.GetHeaders(&types.ReqBlocks{})
if err != nil { if err != nil {
...@@ -627,6 +635,7 @@ func TestJsonRPC(t *testing.T) { ...@@ -627,6 +635,7 @@ func TestJsonRPC(t *testing.T) {
testGetLastHeaderJsonRPC(t, &jrpc) testGetLastHeaderJsonRPC(t, &jrpc)
testGetMempoolJsonRPC(t, &jrpc) testGetMempoolJsonRPC(t, &jrpc)
testGetLastMemPoolJsonRPC(t, &jrpc) testGetLastMemPoolJsonRPC(t, &jrpc)
testGetProperFeeJsonRPC(t, &jrpc)
testGenSeedsonRPC(t, &jrpc) testGenSeedsonRPC(t, &jrpc)
testGetPeerInfoJsonRPC(t, &jrpc) testGetPeerInfoJsonRPC(t, &jrpc)
testIsNtpClockSyncJsonRPC(t, &jrpc) testIsNtpClockSyncJsonRPC(t, &jrpc)
...@@ -723,6 +732,15 @@ func testGetLastMemPoolJsonRPC(t *testing.T, rpc *mockJRPCSystem) { ...@@ -723,6 +732,15 @@ func testGetLastMemPoolJsonRPC(t *testing.T, rpc *mockJRPCSystem) {
} }
} }
func testGetProperFeeJsonRPC(t *testing.T, rpc *mockJRPCSystem) {
var res rpctypes.ReplyProperFee
err := rpc.newRpcCtx("Chain33.GetProperFee",
nil, &res)
if err != nil {
t.Error("testGetProperFeeJsonRPC failed. Error", err)
}
}
func testGetMempoolJsonRPC(t *testing.T, rpc *mockJRPCSystem) { func testGetMempoolJsonRPC(t *testing.T, rpc *mockJRPCSystem) {
var res rpctypes.ReplyTxList var res rpctypes.ReplyTxList
err := rpc.newRpcCtx("Chain33.GetMempool", err := rpc.newRpcCtx("Chain33.GetMempool",
...@@ -820,6 +838,7 @@ func TestGRPC(t *testing.T) { ...@@ -820,6 +838,7 @@ func TestGRPC(t *testing.T) {
testUnLockGRPC(t, &grpcMock) testUnLockGRPC(t, &grpcMock)
testGetPeerInfoGRPC(t, &grpcMock) testGetPeerInfoGRPC(t, &grpcMock)
testGetLastMemPoolGRPC(t, &grpcMock) testGetLastMemPoolGRPC(t, &grpcMock)
testGetProperFeeGRPC(t, &grpcMock)
testGetWalletStatusGRPC(t, &grpcMock) testGetWalletStatusGRPC(t, &grpcMock)
testGetBlockOverviewGRPC(t, &grpcMock) testGetBlockOverviewGRPC(t, &grpcMock)
testGetAddrOverviewGRPC(t, &grpcMock) testGetAddrOverviewGRPC(t, &grpcMock)
...@@ -969,6 +988,14 @@ func testGetLastMemPoolGRPC(t *testing.T, rpc *mockGRPCSystem) { ...@@ -969,6 +988,14 @@ func testGetLastMemPoolGRPC(t *testing.T, rpc *mockGRPCSystem) {
} }
} }
func testGetProperFeeGRPC(t *testing.T, rpc *mockGRPCSystem) {
var res types.ReplyProperFee
err := rpc.newRpcCtx("GetProperFee", &types.ReqNil{}, &res)
if err != nil {
t.Error("Call GetProperFee Failed.", err)
}
}
func testGetPeerInfoGRPC(t *testing.T, rpc *mockGRPCSystem) { func testGetPeerInfoGRPC(t *testing.T, rpc *mockGRPCSystem) {
var res types.PeerList var res types.PeerList
err := rpc.newRpcCtx("GetPeerInfo", &types.ReqNil{}, &res) err := rpc.newRpcCtx("GetPeerInfo", &types.ReqNil{}, &res)
......
...@@ -24,6 +24,8 @@ type QueueProtocolAPI interface { ...@@ -24,6 +24,8 @@ type QueueProtocolAPI interface {
GetMempool() (*types.ReplyTxList, error) GetMempool() (*types.ReplyTxList, error)
// types.EventGetLastMempool // types.EventGetLastMempool
GetLastMempool() (*types.ReplyTxList, error) GetLastMempool() (*types.ReplyTxList, error)
// types.EventGetProperFee
GetProperFee() (*types.ReplyProperFee, error)
// +++++++++++++++ execs interfaces begin // +++++++++++++++ execs interfaces begin
// types.EventBlockChainQuery // types.EventBlockChainQuery
Query(driver, funcname string, param types.Message) (types.Message, error) Query(driver, funcname string, param types.Message) (types.Message, error)
......
...@@ -225,6 +225,12 @@ func (c *GrpcCtx) Run() (err error) { ...@@ -225,6 +225,12 @@ func (c *GrpcCtx) Run() (err error) {
*c.Res.(*types.ReplyTxList) = *reply *c.Res.(*types.ReplyTxList) = *reply
} }
errRet = err errRet = err
case "GetProperFee":
reply, err := rpc.GetProperFee(context.Background(), c.Params.(*types.ReqNil))
if err == nil {
*c.Res.(*types.ReplyProperFee) = *reply
}
errRet = err
case "GetWalletStatus": case "GetWalletStatus":
reply, err := rpc.GetWalletStatus(context.Background(), c.Params.(*types.ReqNil)) reply, err := rpc.GetWalletStatus(context.Background(), c.Params.(*types.ReqNil))
if err == nil { if err == nil {
......
...@@ -208,6 +208,11 @@ func (g *Grpc) GetLastMemPool(ctx context.Context, in *pb.ReqNil) (*pb.ReplyTxLi ...@@ -208,6 +208,11 @@ func (g *Grpc) GetLastMemPool(ctx context.Context, in *pb.ReqNil) (*pb.ReplyTxLi
return g.cli.GetLastMempool() return g.cli.GetLastMempool()
} }
// GetProperFee return last mempool proper fee
func (g *Grpc) GetProperFee(ctx context.Context, in *pb.ReqNil) (*pb.ReplyProperFee, error) {
return g.cli.GetProperFee()
}
// GetBlockOverview get block overview // GetBlockOverview get block overview
// GetBlockOverview(parm *types.ReqHash) (*types.BlockOverview, error) //add by hyb // GetBlockOverview(parm *types.ReqHash) (*types.BlockOverview, error) //add by hyb
func (g *Grpc) GetBlockOverview(ctx context.Context, in *pb.ReqHash) (*pb.BlockOverview, error) { func (g *Grpc) GetBlockOverview(ctx context.Context, in *pb.ReqHash) (*pb.BlockOverview, error) {
......
...@@ -202,6 +202,18 @@ func TestGetLastMemPool(t *testing.T) { ...@@ -202,6 +202,18 @@ func TestGetLastMemPool(t *testing.T) {
testGetLastMemPoolOK(t) testGetLastMemPoolOK(t)
} }
func testGetProperFeeOK(t *testing.T) {
qapi.On("GetProperFee").Return(nil, nil)
data, err := g.GetProperFee(getOkCtx(), nil)
assert.Nil(t, err, "the error should be nil")
assert.Nil(t, data)
}
func TestGetProperFee(t *testing.T) {
testGetProperFeeOK(t)
}
//func (g *Grpc) QueryChain(ctx context.Context, in *pb.Query) (*pb.Reply, error) { //func (g *Grpc) QueryChain(ctx context.Context, in *pb.Query) (*pb.Reply, error) {
// if !g.checkWhitlist(ctx) { // if !g.checkWhitlist(ctx) {
// return nil, fmt.Errorf("reject") // return nil, fmt.Errorf("reject")
......
...@@ -616,6 +616,18 @@ func (c *Chain33) GetLastMemPool(in types.ReqNil, result *interface{}) error { ...@@ -616,6 +616,18 @@ func (c *Chain33) GetLastMemPool(in types.ReqNil, result *interface{}) error {
return nil return nil
} }
// GetProperFee get contents in proper fee
func (c *Chain33) GetProperFee(in types.ReqNil, result *interface{}) error {
reply, err := c.cli.GetProperFee()
if err != nil {
return err
}
var properFee rpctypes.ReplyProperFee
properFee.ProperFee = reply.GetProperFee()
*result = &properFee
return nil
}
// GetBlockOverview get overview of block // GetBlockOverview get overview of block
// GetBlockOverview(parm *types.ReqHash) (*types.BlockOverview, error) // GetBlockOverview(parm *types.ReqHash) (*types.BlockOverview, error)
func (c *Chain33) GetBlockOverview(in rpctypes.QueryParm, result *interface{}) error { func (c *Chain33) GetBlockOverview(in rpctypes.QueryParm, result *interface{}) error {
......
...@@ -1019,6 +1019,23 @@ func TestChain33_GetLastMemPool(t *testing.T) { ...@@ -1019,6 +1019,23 @@ func TestChain33_GetLastMemPool(t *testing.T) {
mock.AssertExpectationsForObjects(t, api) mock.AssertExpectationsForObjects(t, api)
} }
func TestChain33_GetProperFee(t *testing.T) {
api := new(mocks.QueueProtocolAPI)
testChain33 := newTestChain33(api)
// expected := &types.ReqBlocks{}
api.On("GetProperFee").Return(nil, errors.New("error value"))
var testResult interface{}
actual := types.ReqNil{}
err := testChain33.GetProperFee(actual, &testResult)
t.Log(err)
assert.Equal(t, nil, testResult)
assert.NotNil(t, err)
mock.AssertExpectationsForObjects(t, api)
}
func TestChain33_GetBlockOverview(t *testing.T) { func TestChain33_GetBlockOverview(t *testing.T) {
api := new(mocks.QueueProtocolAPI) api := new(mocks.QueueProtocolAPI)
testChain33 := newTestChain33(api) testChain33 := newTestChain33(api)
......
...@@ -173,6 +173,11 @@ type ReplyTxList struct { ...@@ -173,6 +173,11 @@ type ReplyTxList struct {
Txs []*Transaction `json:"txs"` Txs []*Transaction `json:"txs"`
} }
// ReplyTxList reply tx list
type ReplyProperFee struct {
ProperFee int64 `json:"properFee"`
}
// ReplyHash reply hash string json // ReplyHash reply hash string json
type ReplyHash struct { type ReplyHash struct {
Hash string `json:"hash"` Hash string `json:"hash"`
......
...@@ -22,6 +22,7 @@ func MempoolCmd() *cobra.Command { ...@@ -22,6 +22,7 @@ func MempoolCmd() *cobra.Command {
cmd.AddCommand( cmd.AddCommand(
GetMempoolCmd(), GetMempoolCmd(),
GetLastMempoolCmd(), GetLastMempoolCmd(),
GetProperFeeCmd(),
) )
return cmd return cmd
...@@ -80,3 +81,21 @@ func parselastMempoolTxsRes(arg interface{}) (interface{}, error) { ...@@ -80,3 +81,21 @@ func parselastMempoolTxsRes(arg interface{}) (interface{}, error) {
} }
return result, nil return result, nil
} }
// GetProperFeeCmd get last proper fee
func GetProperFeeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "proper_fee",
Short: "Get latest proper fee",
Run: properFee,
}
return cmd
}
func properFee(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
var res rpctypes.ReplyProperFee
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.GetProperFee", nil, &res)
ctx.SetResultCb(nil)
ctx.Run()
}
...@@ -16,6 +16,7 @@ type QueueCache interface { ...@@ -16,6 +16,7 @@ type QueueCache interface {
Remove(hash string) error Remove(hash string) error
Size() int Size() int
Walk(count int, cb func(tx *Item) bool) Walk(count int, cb func(tx *Item) bool)
GetProperFee() int64
} }
// Item 为Mempool中包装交易的数据结构 // Item 为Mempool中包装交易的数据结构
......
...@@ -87,6 +87,9 @@ func (mem *Mempool) eventProcess() { ...@@ -87,6 +87,9 @@ func (mem *Mempool) eventProcess() {
case types.EventGetAddrTxs: case types.EventGetAddrTxs:
// 获取mempool中对应账户(组)所有交易 // 获取mempool中对应账户(组)所有交易
mem.eventGetAddrTxs(msg) mem.eventGetAddrTxs(msg)
case types.EventGetProperFee:
// 获取对应排队策略中合适的手续费
mem.eventGetProperFee(msg)
default: default:
} }
mlog.Debug("mempool", "cost", types.Since(beg), "msg", types.GetEventName(int(msg.Ty))) mlog.Debug("mempool", "cost", types.Since(beg), "msg", types.GetEventName(int(msg.Ty)))
...@@ -186,6 +189,13 @@ func (mem *Mempool) eventGetAddrTxs(msg *queue.Message) { ...@@ -186,6 +189,13 @@ func (mem *Mempool) eventGetAddrTxs(msg *queue.Message) {
msg.Reply(mem.client.NewMessage("", types.EventReplyAddrTxs, txlist)) msg.Reply(mem.client.NewMessage("", types.EventReplyAddrTxs, txlist))
} }
// eventGetProperFee 获取排队策略中合适的手续费
func (mem *Mempool) eventGetProperFee(msg *queue.Message) {
properFee := mem.cache.qcache.GetProperFee()
msg.Reply(mem.client.NewMessage("rpc", types.EventReplyProperFee,
&types.ReplyProperFee{ProperFee: properFee}))
}
func (mem *Mempool) checkSign(data *queue.Message) *queue.Message { func (mem *Mempool) checkSign(data *queue.Message) *queue.Message {
tx, ok := data.GetData().(types.TxGroup) tx, ok := data.GetData().(types.TxGroup)
if ok && tx.CheckSign() { if ok && tx.CheckSign() {
......
...@@ -124,8 +124,9 @@ func initEnv3() (queue.Queue, queue.Module, queue.Module, *Mempool) { ...@@ -124,8 +124,9 @@ func initEnv3() (queue.Queue, queue.Module, queue.Module, *Mempool) {
types.SetMinFee(0) types.SetMinFee(0)
s := store.New(cfg.Store, sub.Store) s := store.New(cfg.Store, sub.Store)
s.SetQueueClient(q.Client()) s.SetQueueClient(q.Client())
subConfig := SubConfig{cfg.Mempool.PoolCacheSize, cfg.Mempool.MinTxFee}
mem := NewMempool(cfg.Mempool) mem := NewMempool(cfg.Mempool)
mem.SetQueueCache(NewSimpleQueue(int(cfg.Mempool.PoolCacheSize))) mem.SetQueueCache(NewSimpleQueue(subConfig))
mem.SetQueueClient(q.Client()) mem.SetQueueClient(q.Client())
mem.Wait() mem.Wait()
return q, chain, s, mem return q, chain, s, mem
...@@ -138,8 +139,9 @@ func initEnv2(size int) (queue.Queue, *Mempool) { ...@@ -138,8 +139,9 @@ func initEnv2(size int) (queue.Queue, *Mempool) {
blockchainProcess(q) blockchainProcess(q)
execProcess(q) execProcess(q)
cfg.Mempool.PoolCacheSize = int64(size) cfg.Mempool.PoolCacheSize = int64(size)
subConfig := SubConfig{cfg.Mempool.PoolCacheSize, cfg.Mempool.MinTxFee}
mem := NewMempool(cfg.Mempool) mem := NewMempool(cfg.Mempool)
mem.SetQueueCache(NewSimpleQueue(size)) mem.SetQueueCache(NewSimpleQueue(subConfig))
mem.SetQueueClient(q.Client()) mem.SetQueueClient(q.Client())
mem.setSync(true) mem.setSync(true)
mem.SetMinFee(0) mem.SetMinFee(0)
...@@ -157,8 +159,9 @@ func initEnv(size int) (queue.Queue, *Mempool) { ...@@ -157,8 +159,9 @@ func initEnv(size int) (queue.Queue, *Mempool) {
blockchainProcess(q) blockchainProcess(q)
execProcess(q) execProcess(q)
cfg.Mempool.PoolCacheSize = int64(size) cfg.Mempool.PoolCacheSize = int64(size)
subConfig := SubConfig{cfg.Mempool.PoolCacheSize, cfg.Mempool.MinTxFee}
mem := NewMempool(cfg.Mempool) mem := NewMempool(cfg.Mempool)
mem.SetQueueCache(NewSimpleQueue(size)) mem.SetQueueCache(NewSimpleQueue(subConfig))
mem.SetQueueClient(q.Client()) mem.SetQueueClient(q.Client())
mem.setSync(true) mem.setSync(true)
mem.SetMinFee(types.GInt("MinFee")) mem.SetMinFee(types.GInt("MinFee"))
...@@ -567,6 +570,37 @@ func TestGetLatestTx(t *testing.T) { ...@@ -567,6 +570,37 @@ func TestGetLatestTx(t *testing.T) {
} }
} }
func TestGetProperFee(t *testing.T) {
q, mem := initEnv(0)
defer q.Close()
defer mem.Close()
// add 10 txs
err := add10Tx(mem.client)
if err != nil {
t.Error("add tx error", err.Error())
return
}
msg11 := mem.client.NewMessage("mempool", types.EventTx, tx11)
mem.client.Send(msg11, true)
mem.client.Wait(msg11)
msg := mem.client.NewMessage("mempool", types.EventGetProperFee, nil)
mem.client.Send(msg, true)
reply, err := mem.client.Wait(msg)
if err != nil {
t.Error(err)
return
}
if reply.GetData().(*types.ReplyProperFee).GetProperFee() != mem.cfg.MinTxFee {
t.Error("TestGetProperFee failed", reply.GetData().(*types.ReplyProperFee).GetProperFee(), mem.cfg.MinTxFee)
}
}
func TestCheckLowFee(t *testing.T) { func TestCheckLowFee(t *testing.T) {
q, mem := initEnv(0) q, mem := initEnv(0)
defer q.Close() defer q.Close()
......
...@@ -9,17 +9,22 @@ import ( ...@@ -9,17 +9,22 @@ import (
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
) )
type SubConfig struct {
PoolCacheSize int64 `json:"poolCacheSize"`
ProperFee int64 `json:"properFee"`
}
//SimpleQueue 简单队列模式(默认提供一个队列,便于测试) //SimpleQueue 简单队列模式(默认提供一个队列,便于测试)
type SimpleQueue struct { type SimpleQueue struct {
txList *listmap.ListMap txList *listmap.ListMap
maxsize int subConfig SubConfig
} }
//NewSimpleQueue 创建队列 //NewSimpleQueue 创建队列
func NewSimpleQueue(cacheSize int) *SimpleQueue { func NewSimpleQueue(subConfig SubConfig) *SimpleQueue {
return &SimpleQueue{ return &SimpleQueue{
txList: listmap.New(), txList: listmap.New(),
maxsize: cacheSize, subConfig: subConfig,
} }
} }
...@@ -43,7 +48,7 @@ func (cache *SimpleQueue) Push(tx *Item) error { ...@@ -43,7 +48,7 @@ func (cache *SimpleQueue) Push(tx *Item) error {
if cache.Exist(string(hash)) { if cache.Exist(string(hash)) {
return types.ErrTxExist return types.ErrTxExist
} }
if cache.txList.Size() >= cache.maxsize { if cache.txList.Size() >= int(cache.subConfig.PoolCacheSize) {
return types.ErrMemFull return types.ErrMemFull
} }
cache.txList.Push(string(hash), tx) cache.txList.Push(string(hash), tx)
...@@ -72,3 +77,8 @@ func (cache *SimpleQueue) Walk(count int, cb func(value *Item) bool) { ...@@ -72,3 +77,8 @@ func (cache *SimpleQueue) Walk(count int, cb func(value *Item) bool) {
return i != count return i != count
}) })
} }
// GetProperFee 获取合适的手续费
func (cache *SimpleQueue) GetProperFee() int64 {
return cache.subConfig.ProperFee
}
...@@ -12,7 +12,8 @@ import ( ...@@ -12,7 +12,8 @@ import (
) )
func TestCache(t *testing.T) { func TestCache(t *testing.T) {
cache := NewSimpleQueue(1) subConfig := SubConfig{1, 100000}
cache := NewSimpleQueue(subConfig)
tx := &types.Transaction{Payload: []byte("123")} tx := &types.Transaction{Payload: []byte("123")}
hash := string(tx.Hash()) hash := string(tx.Hash())
assert.Equal(t, false, cache.Exist(hash)) assert.Equal(t, false, cache.Exist(hash))
...@@ -38,7 +39,8 @@ func TestCache(t *testing.T) { ...@@ -38,7 +39,8 @@ func TestCache(t *testing.T) {
cache.Remove(hash) cache.Remove(hash)
assert.Equal(t, 0, cache.Size()) assert.Equal(t, 0, cache.Size())
//push to item //push to item
cache = NewSimpleQueue(2) subConfig = SubConfig{2, 100000}
cache = NewSimpleQueue(subConfig)
cache.Push(item1) cache.Push(item1)
cache.Push(item2) cache.Push(item2)
assert.Equal(t, 2, cache.Size()) assert.Equal(t, 2, cache.Size())
...@@ -69,4 +71,7 @@ func TestCache(t *testing.T) { ...@@ -69,4 +71,7 @@ func TestCache(t *testing.T) {
return false return false
}) })
assert.Equal(t, 1, i) assert.Equal(t, 1, i)
//test timeline GetProperFee
assert.Equal(t, int64(100000), cache.GetProperFee())
} }
...@@ -14,18 +14,17 @@ func init() { ...@@ -14,18 +14,17 @@ func init() {
drivers.Reg("timeline", New) drivers.Reg("timeline", New)
} }
type subConfig struct {
PoolCacheSize int64 `json:"poolCacheSize"`
}
//New 创建timeline cache 结构的 mempool //New 创建timeline cache 结构的 mempool
func New(cfg *types.Mempool, sub []byte) queue.Module { func New(cfg *types.Mempool, sub []byte) queue.Module {
c := drivers.NewMempool(cfg) c := drivers.NewMempool(cfg)
var subcfg subConfig var subcfg drivers.SubConfig
types.MustDecode(sub, &subcfg) types.MustDecode(sub, &subcfg)
if subcfg.PoolCacheSize == 0 { if subcfg.PoolCacheSize == 0 {
subcfg.PoolCacheSize = cfg.PoolCacheSize subcfg.PoolCacheSize = cfg.PoolCacheSize
} }
c.SetQueueCache(drivers.NewSimpleQueue(int(subcfg.PoolCacheSize))) if subcfg.ProperFee == 0 {
subcfg.ProperFee = cfg.MinTxFee
}
c.SetQueueCache(drivers.NewSimpleQueue(subcfg))
return c return c
} }
...@@ -58,13 +58,13 @@ type Mempool struct { ...@@ -58,13 +58,13 @@ type Mempool struct {
// mempool队列名称,可配,timeline,score,price // mempool队列名称,可配,timeline,score,price
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
// mempool缓存容量大小,默认10240 // mempool缓存容量大小,默认10240
PoolCacheSize int64 `protobuf:"varint,1,opt,name=poolCacheSize" json:"poolCacheSize,omitempty"` PoolCacheSize int64 `protobuf:"varint,2,opt,name=poolCacheSize" json:"poolCacheSize,omitempty"`
// 最小得交易手续费用,这个没有默认值,必填,一般是100000 // 最小得交易手续费用,这个没有默认值,必填,一般是100000
MinTxFee int64 `protobuf:"varint,2,opt,name=minTxFee" json:"minTxFee,omitempty"` MinTxFee int64 `protobuf:"varint,3,opt,name=minTxFee" json:"minTxFee,omitempty"`
ForceAccept bool `protobuf:"varint,3,opt,name=forceAccept" json:"forceAccept,omitempty"` ForceAccept bool `protobuf:"varint,4,opt,name=forceAccept" json:"forceAccept,omitempty"`
// 每个账户在mempool中得最大交易数量,默认100 // 每个账户在mempool中得最大交易数量,默认100
MaxTxNumPerAccount int64 `protobuf:"varint,4,opt,name=maxTxNumPerAccount" json:"maxTxNumPerAccount,omitempty"` MaxTxNumPerAccount int64 `protobuf:"varint,5,opt,name=maxTxNumPerAccount" json:"maxTxNumPerAccount,omitempty"`
MaxTxLast int64 `protobuf:"varint,4,opt,name=maxTxLast" json:"maxTxLast,omitempty"` MaxTxLast int64 `protobuf:"varint,6,opt,name=maxTxLast" json:"maxTxLast,omitempty"`
} }
// Consensus 配置 // Consensus 配置
......
...@@ -146,6 +146,11 @@ const ( ...@@ -146,6 +146,11 @@ const (
EventLocalRollback = 137 EventLocalRollback = 137
EventLocalNew = 138 EventLocalNew = 138
EventLocalClose = 139 EventLocalClose = 139
//mempool
EventGetProperFee = 140
EventReplyProperFee = 141
//exec //exec
EventBlockChainQuery = 212 EventBlockChainQuery = 212
EventConsensusQuery = 213 EventConsensusQuery = 213
...@@ -290,4 +295,8 @@ var eventName = map[int]string{ ...@@ -290,4 +295,8 @@ var eventName = map[int]string{
EventLocalRollback: "EventLocalRollback", EventLocalRollback: "EventLocalRollback",
EventLocalNew: "EventLocalNew", EventLocalNew: "EventLocalNew",
EventLocalClose: "EventLocalClose", EventLocalClose: "EventLocalClose",
//mempool
EventGetProperFee: "EventGetProperFee",
EventReplyProperFee: "EventReplyProperFee",
} }
...@@ -672,6 +672,36 @@ func (_m *Chain33Client) GetLastHeader(ctx context.Context, in *types.ReqNil, op ...@@ -672,6 +672,36 @@ func (_m *Chain33Client) GetLastHeader(ctx context.Context, in *types.ReqNil, op
return r0, r1 return r0, r1
} }
// GetProperFee provides a mock function with given fields: ctx, in, opts
func (_m *Chain33Client) GetProperFee(ctx context.Context, in *types.ReqNil, opts ...grpc.CallOption) (*types.ReplyProperFee, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, in)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *types.ReplyProperFee
if rf, ok := ret.Get(0).(func(context.Context, *types.ReqNil, ...grpc.CallOption) *types.ReplyProperFee); ok {
r0 = rf(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*types.ReplyProperFee)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *types.ReqNil, ...grpc.CallOption) error); ok {
r1 = rf(ctx, in, opts...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetLastMemPool provides a mock function with given fields: ctx, in, opts // GetLastMemPool provides a mock function with given fields: ctx, in, opts
func (_m *Chain33Client) GetLastMemPool(ctx context.Context, in *types.ReqNil, opts ...grpc.CallOption) (*types.ReplyTxList, error) { func (_m *Chain33Client) GetLastMemPool(ctx context.Context, in *types.ReqNil, opts ...grpc.CallOption) (*types.ReplyTxList, error) {
_va := make([]interface{}, len(opts)) _va := make([]interface{}, len(opts))
......
...@@ -76,6 +76,9 @@ service chain33 { ...@@ -76,6 +76,9 @@ service chain33 {
//获取最新的Mempool //获取最新的Mempool
rpc GetLastMemPool(ReqNil) returns (ReplyTxList) {} rpc GetLastMemPool(ReqNil) returns (ReplyTxList) {}
//获取最新的ProperFee
rpc GetProperFee(ReqNil) returns (ReplyProperFee) {}
// 获取钱包状态 // 获取钱包状态
rpc GetWalletStatus(ReqNil) returns (WalletStatus) {} rpc GetWalletStatus(ReqNil) returns (WalletStatus) {}
//区块浏览器接口 //区块浏览器接口
......
...@@ -171,6 +171,10 @@ message ReplyTxList { ...@@ -171,6 +171,10 @@ message ReplyTxList {
repeated Transaction txs = 1; repeated Transaction txs = 1;
} }
message ReplyProperFee {
int64 properFee = 1;
}
message TxHashList { message TxHashList {
repeated bytes hashes = 1; repeated bytes hashes = 1;
int64 count = 2; int64 count = 2;
......
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