Commit 47bbff03 authored by 陈德海's avatar 陈德海

merge mempool trade

parents 053827a8 5e735848
......@@ -62,7 +62,7 @@ grpcFuncWhitelist=["*"]
[mempool]
name="trade"
name="timeline"
poolCacheSize=10240
minTxFee=100000
maxTxNumPerAccount=10000
......@@ -77,8 +77,8 @@ poolCacheSize=10240
minTxFee=100000
maxTxNumPerAccount=10000
timeParam=1 #时间占价格比例
priceConstant=1 #一个合适的常量
pricePower=0 #手续费占常量比例
priceConstant=1544 #手续费相对于时间的一个合适的常量,取当前unxi时间戳前四位数,排序时手续费高1e-5~=快1s
pricePower=1 #常量比例
[consensus]
name="ticket"
......
......@@ -48,7 +48,7 @@ type suiteParaCommitMsg struct {
block *blockchain.BlockChain
exec *executor.Executor
store queue.Module
mem *mempool.Mempool
mem queue.Module
network *p2p.P2p
}
......@@ -84,17 +84,15 @@ func (s *suiteParaCommitMsg) initEnv(cfg *types.Config, sub *types.ConfigSubModu
s.para.grpcClient = s.grpcCli
s.para.SetQueueClient(q.Client())
s.mem = mempool.New(cfg.MemPool)
s.mem = mempool.New(cfg.Mempool, nil)
s.mem.SetQueueClient(q.Client())
s.mem.SetSync(true)
s.mem.WaitPollLastHeader()
s.mem.Wait()
s.network = p2p.New(cfg.P2P)
s.network.SetQueueClient(q.Client())
s.para.wg.Add(1)
go walletProcess(q, s.para)
}
func walletProcess(q queue.Queue, para *client) {
......
......@@ -51,6 +51,7 @@ verMix=118
verMax=119
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
......
......@@ -62,14 +62,14 @@ func TestPbft(t *testing.T) {
clearTestData()
}
func initEnvPbft() (queue.Queue, *blockchain.BlockChain, *p2p.P2p, queue.Module, *mempool.Mempool, queue.Module, queue.Module, queue.Module) {
func initEnvPbft() (queue.Queue, *blockchain.BlockChain, *p2p.P2p, queue.Module, queue.Module, *executor.Executor, queue.Module, queue.Module) {
var q = queue.New("channel")
flag.Parse()
cfg, sub := types.InitCfg("chain33.test.toml")
types.Init(cfg.Title, cfg)
chain := blockchain.New(cfg.BlockChain)
chain.SetQueueClient(q.Client())
mem := mempool.New(cfg.MemPool)
mem := mempool.New(cfg.Mempool, nil)
mem.SetQueueClient(q.Client())
exec := executor.New(cfg.Exec, sub.Exec)
exec.SetQueueClient(q.Client())
......
......@@ -59,6 +59,7 @@ jrpcFuncWhitelist=["*"]
grpcFuncWhitelist=["*"]
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
......
......@@ -63,7 +63,7 @@ func RaftPerf() {
sendReplyList(q)
}
func initEnvRaft() (queue.Queue, *blockchain.BlockChain, queue.Module, *mempool.Mempool, queue.Module, queue.Module, queue.Module) {
func initEnvRaft() (queue.Queue, *blockchain.BlockChain, queue.Module, queue.Module, *executor.Executor, queue.Module, queue.Module) {
var q = queue.New("channel")
flag.Parse()
cfg, sub := types.InitCfg("chain33.test.toml")
......@@ -80,7 +80,7 @@ func initEnvRaft() (queue.Queue, *blockchain.BlockChain, queue.Module, *mempool.
cs := NewRaftCluster(cfg.Consensus, sub.Consensus["raft"])
cs.SetQueueClient(q.Client())
mem := mempool.New(cfg.MemPool)
mem := mempool.New(cfg.Mempool, nil)
mem.SetQueueClient(q.Client())
network := p2p.New(cfg.P2P)
......
......@@ -60,6 +60,7 @@ jrpcFuncWhitelist=["*"]
grpcFuncWhitelist=["*"]
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
......
......@@ -76,7 +76,7 @@ func RaftPerf() {
time.Sleep(10 * time.Second)
}
func initEnvTendermint() (queue.Queue, *blockchain.BlockChain, queue.Module, *mempool.Mempool, queue.Module, queue.Module, queue.Module) {
func initEnvTendermint() (queue.Queue, *blockchain.BlockChain, queue.Module, queue.Module, *executor.Executor, queue.Module, queue.Module) {
var q = queue.New("channel")
flag.Parse()
cfg, sub := types.InitCfg("chain33.test.toml")
......@@ -93,7 +93,7 @@ func initEnvTendermint() (queue.Queue, *blockchain.BlockChain, queue.Module, *me
cs := New(cfg.Consensus, sub.Consensus["tendermint"])
cs.SetQueueClient(q.Client())
mem := mempool.New(cfg.MemPool)
mem := mempool.New(cfg.Mempool, nil)
mem.SetQueueClient(q.Client())
network := p2p.New(cfg.P2P)
......
......@@ -60,6 +60,7 @@ jrpcFuncWhitelist=["*"]
grpcFuncWhitelist=["*"]
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
maxTxNumPerAccount=10000
......
......@@ -201,6 +201,11 @@ func (client *Client) setTicket(tlist *ty.ReplyTicketList, privmap map[string]cr
client.ticketmu.Lock()
defer client.ticketmu.Unlock()
client.ticketsMap = make(map[string]*ty.Ticket)
if tlist == nil || privmap == nil {
client.ticketsMap = nil
client.privmap = nil
return
}
for _, ticket := range tlist.Tickets {
client.ticketsMap[ticket.GetTicketId()] = ticket
}
......
......@@ -104,11 +104,29 @@ func TestTicketMap(t *testing.T) {
{TicketId: "3333"},
{TicketId: "4444"},
}
privmap := make(map[string]crypto.PrivKey)
//通过privkey生成一个pubkey然后换算成对应的addr
cr, _ := crypto.New("secp256k1")
priv, _ := cr.PrivKeyFromBytes([]byte("2116459C0EC8ED01AA0EEAE35CAC5C96F94473F7816F114873291217303F6989"))
privmap["1111"] = priv
privmap["2222"] = priv
privmap["3333"] = priv
privmap["4444"] = priv
assert.Equal(t, c.getTicketCount(), int64(0))
c.setTicket(ticketList, nil)
c.setTicket(ticketList, privmap)
assert.Equal(t, c.getTicketCount(), int64(4))
c.delTicket("3333")
assert.Equal(t, c.getTicketCount(), int64(3))
c.setTicket(ticketList, nil)
assert.Equal(t, c.getTicketCount(), int64(0))
c.setTicket(nil, privmap)
assert.Equal(t, c.getTicketCount(), int64(0))
c.setTicket(nil, nil)
assert.Equal(t, c.getTicketCount(), int64(0))
}
func TestProcEvent(t *testing.T) {
......
......@@ -62,6 +62,7 @@ grpcFuncWhitelist=["*"]
mainnetJrpcAddr= "http://localhost:8801"
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
maxTxNumPerAccount=10000
......
......@@ -63,6 +63,7 @@ grpcFuncWhitelist=["*"]
mainnetJrpcAddr= "http://localhost:8801"
[mempool]
name="timeline"
poolCacheSize=10240
minTxFee=100000
maxTxNumPerAccount=10000
......
......@@ -100,9 +100,8 @@ func (mock *testDataMock) initMember() {
if mock.mockMempool {
mock.mockMempoolProc(q)
} else {
mempool := mempool.New(cfg.MemPool)
mempool := mempool.New(cfg.Mempool, nil)
mempool.SetQueueClient(q.Client())
mempool.SetMinFee(1e5)
mock.modules = append(mock.modules, mempool)
}
......
......@@ -5,6 +5,8 @@
package executor
import (
"errors"
"fmt"
"strconv"
"github.com/33cn/chain33/account"
......@@ -412,10 +414,34 @@ func (action *tradeAction) tradeRevokeSell(revoke *pty.TradeForRevokeSell) (*typ
return &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}, nil
}
//不同合约之间查询的需求后面要考虑,现在先重复处理一下,原则上不能直接引用其他合约的代码
//后面可能会有一套查询规则 和 写规则, 合约对其他合约只读
func calcTokenKey(token string) (key []byte) {
tokenCreated := "mavl-token-"
return []byte(fmt.Sprintf(tokenCreated+"%s", token))
}
func checkTokenExist(token string, db dbm.KV) bool {
_, err := db.Get(calcTokenKey(token))
return err == nil
}
func (action *tradeAction) tradeBuyLimit(buy *pty.TradeForBuyLimit) (*types.Receipt, error) {
// ErrTokenNotExist error token symbol not exist
errTokenNotExist := errors.New("ErrTokenSymbolNotExist")
if buy.TotalBoardlot < 0 || buy.PricePerBoardlot < 0 || buy.MinBoardlot < 0 || buy.AmountPerBoardlot < 0 {
return nil, types.ErrInvalidParam
}
// 这个检查会比较鸡肋, 按目前的想法的能支持更多的资产, 各种资产检查不一样
// 可以先让订单成功, 如果不合适, 自己撤单也行
// 或后续跨合约注册一个检测的函数
if buy.AssetExec == "" || buy.AssetExec == defaultAssetExec {
// check token exist
if !checkTokenExist(buy.TokenSymbol, action.db) {
return nil, errTokenNotExist
}
}
if !checkAsset(action.height, buy.AssetExec, buy.TokenSymbol) {
return nil, types.ErrInvalidParam
......
......@@ -24,7 +24,4 @@ var (
// TODO
func init() {
processNum = runtime.NumCPU()
//if processNum >= 2 {
//processNum -= 1
//}
}
......@@ -943,7 +943,7 @@ func (bs *BlockStore) saveBlockSequence(storeBatch dbm.Batch, hash []byte, heigh
storeBatch.Set(calcSequenceToHashKey(newSequence), BlockSequenceByte)
//parachain hash->seq 只记录add block时的hash和seq对应关系
if Type == AddBlock && isParaChain {
if Type == AddBlock {
Sequencebytes := types.Encode(&types.Int64{Data: newSequence})
storeBatch.Set(calcHashToSequenceKey(hash), Sequencebytes)
}
......@@ -991,7 +991,7 @@ func (bs *BlockStore) GetSequenceByHash(hash []byte) (int64, error) {
if err != dbm.ErrNotFoundInDb {
storeLog.Error("GetSequenceByHash", "error", err)
}
return -1, types.ErrHeightNotExist
return -1, types.ErrHashNotExist
}
err = types.Decode(seqbytes, &seq)
......
......@@ -634,6 +634,7 @@ func testGetSeqByHash(t *testing.T, blockchain *blockchain.BlockChain) {
reqBlock.IsDetail = true
hashes := make([][]byte, 1)
Sequences, err := blockchain.GetBlockSequences(&reqBlock)
if err == nil && Sequences != nil {
for index, sequence := range Sequences.Items {
hashes[index] = sequence.Hash
......@@ -641,8 +642,8 @@ func testGetSeqByHash(t *testing.T, blockchain *blockchain.BlockChain) {
}
seq, _ := blockchain.ProcGetSeqByHash(hashes[0])
if seq != -1 {
t.Error("testGetSeqByHash only para chain GetSeqByHash ")
if seq == -1 {
t.Error(" GetSeqByHash err")
}
chainlog.Info("testGetSeqByHash end --------------------")
......
......@@ -455,11 +455,13 @@ func (chain *BlockChain) addParaChainBlockDetail(msg queue.Message) {
//parachian 通过blockhash获取对应的seq,只记录了addblock时的seq
func (chain *BlockChain) getSeqByHash(msg queue.Message) {
var sequence types.Int64
blockhash := (msg.Data).(*types.ReqHash)
sequence.Data, _ = chain.ProcGetSeqByHash(blockhash.Hash)
msg.Reply(chain.client.NewMessage("rpc", types.EventGetSeqByHash, &sequence))
seq, err := chain.ProcGetSeqByHash(blockhash.Hash)
if err != nil {
chainlog.Error("getSeqByHash", "err", err.Error())
msg.Reply(chain.client.NewMessage("rpc", types.EventReply, err))
}
msg.Reply(chain.client.NewMessage("rpc", types.EventGetSeqByHash, &types.Int64{Data: seq}))
}
//获取指定前缀key的数量
......
......@@ -25,7 +25,7 @@ func TestReindex(t *testing.T) {
chain := mock33.GetBlockChain()
db := chain.GetDB()
kvs := getAllKeys(db)
assert.Equal(t, len(kvs), 19)
assert.Equal(t, len(kvs), 20)
defer mock33.Close()
txs := util.GenCoinsTxs(mock33.GetGenesisKey(), 10)
for i := 0; i < len(txs); i++ {
......
......@@ -8,7 +8,7 @@ set -o pipefail
# os: ubuntu16.04 x64
#chain33 dapp autotest root directory
declare -a Chain33AutoTestDirs=("system" "plugin" "vendor/github.com/33cn/chain33/system")
declare -a Chain33AutoTestDirs=("system" "plugin" "vendor/github.com/33cn/chain33/system" "vendor/github.com/33cn/plugin/plugin")
#copy auto test to specific directory
# check args
......
......@@ -101,6 +101,9 @@ func (m *mockBlockChain) SetQueueClient(q queue.Queue) {
} else {
msg.ReplyErr("Do not support", types.ErrInvalidParam)
}
case types.EventGetSeqByHash:
msg.Reply(client.NewMessage(blockchainKey, types.EventReplyQuery, &types.Int64{Data: 1}))
case types.EventIsSync:
msg.Reply(client.NewMessage(blockchainKey, types.EventReplyIsSync, &types.IsCaughtUp{}))
case types.EventIsNtpClockSync:
......
......@@ -499,6 +499,29 @@ func (_m *QueueProtocolAPI) GetSeqCallBackLastNum(param *types.ReqString) (*type
return r0, r1
}
// GetSequenceByHash provides a mock function with given fields: param
func (_m *QueueProtocolAPI) GetSequenceByHash(param *types.ReqHash) (*types.Int64, error) {
ret := _m.Called(param)
var r0 *types.Int64
if rf, ok := ret.Get(0).(func(*types.ReqHash) *types.Int64); ok {
r0 = rf(param)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*types.Int64)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(*types.ReqHash) error); ok {
r1 = rf(param)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetTransactionByAddr provides a mock function with given fields: param
func (_m *QueueProtocolAPI) GetTransactionByAddr(param *types.ReqAddr) (*types.ReplyTxInfos, error) {
ret := _m.Called(param)
......
......@@ -898,6 +898,25 @@ func (q *QueueProtocol) GetLastBlockSequence() (*types.Int64, error) {
return nil, types.ErrTypeAsset
}
// GetSequenceByHash 通过hash获取对应的执行序列号
func (q *QueueProtocol) GetSequenceByHash(param *types.ReqHash) (*types.Int64, error) {
if param == nil {
err := types.ErrInvalidParam
log.Error("GetSequenceByHash", "Error", err)
return nil, err
}
msg, err := q.query(blockchainKey, types.EventGetSeqByHash, param)
if err != nil {
log.Error("GetSequenceByHash", "Error", err.Error())
return nil, err
}
if reply, ok := msg.GetData().(*types.Int64); ok {
return reply, nil
}
return nil, types.ErrTypeAsset
}
// WalletCreateTx create transaction
func (q *QueueProtocol) WalletCreateTx(param *types.ReqCreateTransaction) (*types.Transaction, error) {
msg, err := q.query(walletKey, types.EventWalletCreateTx, param)
......
......@@ -806,6 +806,7 @@ func TestGRPC(t *testing.T) {
testGetBlockOverviewGRPC(t, &grpcMock)
testGetAddrOverviewGRPC(t, &grpcMock)
testGetBlockHashGRPC(t, &grpcMock)
testGetSequenceByHashGRPC(t, &grpcMock)
testGenSeedGRPC(t, &grpcMock)
testGetSeedGRPC(t, &grpcMock)
testSaveSeedGRPC(t, &grpcMock)
......@@ -1131,3 +1132,11 @@ func testSendTxGRPC(t *testing.T, rpc *mockGRPCSystem) {
t.Error("Call SendTransaction Failed.", err)
}
}
func testGetSequenceByHashGRPC(t *testing.T, rpc *mockGRPCSystem) {
var res types.Int64
err := rpc.newRpcCtx("GetSequenceByHash", &types.ReqHash{}, &res)
if err != nil {
t.Error("Call GetSequenceByHash Failed.", err)
}
}
......@@ -111,6 +111,8 @@ type QueueProtocolAPI interface {
GetBlockSequences(param *types.ReqBlocks) (*types.BlockSequences, error)
//types.EventGetBlockByHashes:
GetBlockByHashes(param *types.ReqHashes) (*types.BlockDetails, error)
//types.EventGetSequenceByHash:
GetSequenceByHash(param *types.ReqHash) (*types.Int64, error)
// --------------- blockchain interfaces end
......
......@@ -315,6 +315,12 @@ func (c *GrpcCtx) Run() (err error) {
*c.Res.(*types.NodeNetInfo) = *reply
}
errRet = err
case "GetSequenceByHash":
reply, err := rpc.GetSequenceByHash(context.Background(), c.Params.(*types.ReqHash))
if err == nil {
*c.Res.(*types.Int64) = *reply
}
errRet = err
default:
errRet = errors.New(fmt.Sprintf("Unsupport method %v", c.Method))
}
......
......@@ -18,13 +18,24 @@ import (
var addrSeed = []byte("address seed bytes for public key")
var addressCache *lru.Cache
var checkAddressCache *lru.Cache
var multisignCache *lru.Cache
var multiCheckAddressCache *lru.Cache
var errVersion = errors.New("check version error")
//MaxExecNameLength 执行器名最大长度
const MaxExecNameLength = 100
//NormalVer 普通地址的版本号
const NormalVer byte = 0
//MultiSignVer 多重签名地址的版本号
const MultiSignVer byte = 5
func init() {
multisignCache, _ = lru.New(10240)
addressCache, _ = lru.New(10240)
checkAddressCache, _ = lru.New(10240)
multiCheckAddressCache, _ = lru.New(10240)
}
//ExecPubKey 计算公钥
......@@ -44,12 +55,23 @@ func ExecAddress(name string) string {
if value, ok := addressCache.Get(name); ok {
return value.(string)
}
addr := PubKeyToAddress(ExecPubkey(name))
addr := GetExecAddress(name)
addrstr := addr.String()
addressCache.Add(name, addrstr)
return addrstr
}
//MultiSignAddress create a multi sign address
func MultiSignAddress(pubkey []byte) string {
if value, ok := multisignCache.Get(string(pubkey)); ok {
return value.(string)
}
addr := HashToAddress(MultiSignVer, pubkey)
addrstr := addr.String()
multisignCache.Add(string(pubkey), addrstr)
return addrstr
}
//ExecPubkey 计算公钥
func ExecPubkey(name string) []byte {
if len(name) > MaxExecNameLength {
......@@ -64,35 +86,27 @@ func ExecPubkey(name string) []byte {
//GetExecAddress 获取地址
func GetExecAddress(name string) *Address {
if len(name) > MaxExecNameLength {
panic("name too long")
}
var bname [200]byte
buf := append(bname[:0], addrSeed...)
buf = append(buf, []byte(name)...)
hash := common.Sha2Sum(buf)
hash := ExecPubkey(name)
addr := PubKeyToAddress(hash[:])
return addr
}
//PubKeyToAddress 公钥转为地址
func PubKeyToAddress(in []byte) *Address {
return HashToAddress(NormalVer, in)
}
//HashToAddress hash32 to address
func HashToAddress(version byte, in []byte) *Address {
a := new(Address)
a.Pubkey = make([]byte, len(in))
copy(a.Pubkey[:], in[:])
a.Version = 0
a.Version = version
a.Hash160 = common.Rimp160AfterSha256(in)
return a
}
//CheckAddress 检查地址
func CheckAddress(addr string) (e error) {
if value, ok := checkAddressCache.Get(addr); ok {
if value == nil {
return nil
}
return value.(error)
}
func checkAddress(ver byte, addr string) (e error) {
dec := base58.Decode(addr)
if dec == nil {
e = errors.New("Cannot decode b58 string '" + addr + "'")
......@@ -110,6 +124,34 @@ func CheckAddress(addr string) (e error) {
e = errors.New("Address Checksum error")
}
}
if dec[0] != ver {
e = errVersion
}
return e
}
//CheckMultiSignAddress 检查多重签名地址的有效性
func CheckMultiSignAddress(addr string) (e error) {
if value, ok := multiCheckAddressCache.Get(addr); ok {
if value == nil {
return nil
}
return value.(error)
}
e = checkAddress(MultiSignVer, addr)
multiCheckAddressCache.Add(addr, e)
return
}
//CheckAddress 检查地址
func CheckAddress(addr string) (e error) {
if value, ok := checkAddressCache.Get(addr); ok {
if value == nil {
return nil
}
return value.(error)
}
e = checkAddress(NormalVer, addr)
checkAddressCache.Add(addr, e)
return
}
......
......@@ -12,27 +12,42 @@ import (
"time"
"github.com/33cn/chain33/common/crypto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
_ "github.com/33cn/chain33/system/crypto/init"
)
func TestAddress(t *testing.T) {
func genkey() crypto.PrivKey {
c, err := crypto.New("secp256k1")
if err != nil {
t.Error(err)
return
panic(err)
}
key, err := c.GenKey()
if err != nil {
t.Error(err)
return
panic(err)
}
return key
}
func TestAddress(t *testing.T) {
key := genkey()
t.Logf("%X", key.Bytes())
addr := PubKeyToAddress(key.PubKey().Bytes())
t.Log(addr)
}
func TestMultiSignAddress(t *testing.T) {
key := genkey()
addr1 := MultiSignAddress(key.PubKey().Bytes())
addr := MultiSignAddress(key.PubKey().Bytes())
assert.Equal(t, addr1, addr)
err := CheckAddress(addr)
assert.Equal(t, errVersion, err)
err = CheckMultiSignAddress(addr)
assert.Nil(t, err)
t.Log(addr)
}
func TestPubkeyToAddress(t *testing.T) {
pubkey := "024a17b0c6eb3143839482faa7e917c9b90a8cfe5008dff748789b8cea1a3d08d5"
b, err := hex.DecodeString(pubkey)
......@@ -61,6 +76,14 @@ func TestCheckAddress(t *testing.T) {
require.NoError(t, err)
}
func TestExecAddress(t *testing.T) {
assert.Equal(t, "16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp", ExecAddress("ticket"))
assert.Equal(t, "16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp", ExecAddress("ticket"))
addr, err := NewAddrFromString(ExecAddress("ticket"))
assert.Nil(t, err)
assert.Equal(t, addr.Version, NormalVer)
}
func BenchmarkExecAddress(b *testing.B) {
start := time.Now().UnixNano() / 1000000
fmt.Println(start)
......
......@@ -47,6 +47,9 @@ func (c *channelClient) CreateRawTransaction(param *types.CreateTx) ([]byte, err
if param.IsToken {
execer = types.ExecName("token")
}
if param.Execer != "" {
execer = param.Execer
}
return types.CallCreateTx(execer, "", param)
}
......
......@@ -88,23 +88,6 @@ func testCreateRawTransactionCoinTransfer(t *testing.T) {
Note: []byte("note"),
}
//v := &cty.CoinsAction_Transfer{
// Transfer:&cty.CoinsTransfer{
// Amount:ctx.Amount,
// Note:ctx.To,
// },
//}
//transfer := &cty.CoinsAction{
// Value:v,
// Ty:cty.CoinsActionTransfer,
//}
//
//tx := &types.Transaction{
// Execer:[]byte("coins"),
// Payload:types.Encode(transfer),
// To:ctx.To,
//}
client := newTestChannelClient()
txHex, err := client.CreateRawTransaction(&ctx)
assert.Nil(t, err)
......
......@@ -38,7 +38,8 @@ func (g *Grpc) CreateRawTransaction(ctx context.Context, in *pb.CreateTx) (*pb.U
// CreateTransaction create transaction of grpc
func (g *Grpc) CreateTransaction(ctx context.Context, in *pb.CreateTxIn) (*pb.UnsignTx, error) {
exec := pb.LoadExecutorType(string(in.Execer))
execer := pb.ExecName(string(in.Execer))
exec := pb.LoadExecutorType(execer)
if exec == nil {
log.Error("callExecNewTx", "Error", "exec not found")
return nil, pb.ErrNotSupport
......@@ -52,7 +53,7 @@ func (g *Grpc) CreateTransaction(ctx context.Context, in *pb.CreateTxIn) (*pb.Un
if err != nil {
return nil, err
}
reply, err := pb.CallCreateTx(string(in.Execer), in.ActionName, msg)
reply, err := pb.CallCreateTx(execer, in.ActionName, msg)
if err != nil {
return nil, err
}
......@@ -344,6 +345,11 @@ func (g *Grpc) GetBlockByHashes(ctx context.Context, in *pb.ReqHashes) (*pb.Bloc
return g.cli.GetBlockByHashes(in)
}
// GetSequenceByHash get block sequece by hash
func (g *Grpc) GetSequenceByHash(ctx context.Context, in *pb.ReqHash) (*pb.Int64, error) {
return g.cli.GetSequenceByHash(in)
}
// SignRawTx signature rawtransaction
func (g *Grpc) SignRawTx(ctx context.Context, in *pb.ReqSignRawTx) (*pb.ReplySignRawTx, error) {
return g.cli.SignRawTx(in)
......
......@@ -20,12 +20,26 @@ import (
)
// CreateRawTransaction create rawtransaction by jrpc
func (c *Chain33) CreateRawTransaction(in *types.CreateTx, result *interface{}) error {
reply, err := c.cli.CreateRawTransaction(in)
func (c *Chain33) CreateRawTransaction(in *rpctypes.CreateTx, result *interface{}) error {
if in == nil {
log.Error("CreateRawTransaction", "Error", types.ErrInvalidParam)
return types.ErrInvalidParam
}
inpb := &types.CreateTx{
To: in.To,
Amount: in.Amount,
Fee: in.Fee,
Note: []byte(in.Note),
IsWithdraw: in.IsWithdraw,
IsToken: in.IsToken,
TokenSymbol: in.TokenSymbol,
ExecName: in.ExecName,
Execer: in.Execer,
}
reply, err := c.cli.CreateRawTransaction(inpb)
if err != nil {
return err
}
*result = hex.EncodeToString(reply)
return nil
}
......@@ -404,50 +418,6 @@ func (c *Chain33) ImportPrivkey(in types.ReqWalletImportPrivkey, result *interfa
// SendToAddress send to address of coins
func (c *Chain33) SendToAddress(in types.ReqWalletSendToAddress, result *interface{}) error {
log.Debug("Rpc SendToAddress", "Tx", in)
if types.IsPara() {
createTx := &types.CreateTx{
To: in.GetTo(),
Amount: in.GetAmount(),
Fee: 1e5,
Note: in.GetNote(),
IsWithdraw: false,
IsToken: true,
TokenSymbol: in.GetTokenSymbol(),
ExecName: types.ExecName("token"),
}
tx, err := c.cli.CreateRawTransaction(createTx)
if err != nil {
log.Debug("ParaChain CreateRawTransaction", "Error", err.Error())
return err
}
//不需要自己去导出私钥,signRawTx 里面只需带入公钥地址,也回优先去查出相应的私钥,前提是私钥已经导入
reqSignRawTx := &types.ReqSignRawTx{
Addr: in.From,
Privkey: "",
TxHex: hex.EncodeToString(tx),
Expire: "300s",
Index: 0,
Token: "",
}
replySignRawTx, err := c.cli.SignRawTx(reqSignRawTx)
if err != nil {
log.Debug("ParaChain SignRawTx", "Error", err.Error())
return err
}
rawParm := rpctypes.RawParm{
Token: "",
Data: replySignRawTx.GetTxHex(),
}
var txHash interface{}
err = forwardTranToMainNet(rawParm, &txHash)
if err != nil {
log.Debug("ParaChain forwardTranToMainNet", "Error", err.Error())
return err
}
*result = &rpctypes.ReplyHash{Hash: txHash.(string)}
return nil
}
reply, err := c.cli.WalletSendToAddress(&in)
if err != nil {
log.Debug("SendToAddress", "Error", err.Error())
......@@ -1120,7 +1090,7 @@ func (c *Chain33) CreateTransaction(in *rpctypes.CreateTxIn, result *interface{}
if in == nil {
return types.ErrInvalidParam
}
btx, err := types.CallCreateTxJSON(in.Execer, in.ActionName, in.Payload)
btx, err := types.CallCreateTxJSON(types.ExecName(in.Execer), in.ActionName, in.Payload)
if err != nil {
return err
}
......
......@@ -387,11 +387,11 @@ func TestChain33_CreateRawTransaction(t *testing.T) {
assert.Nil(t, testResult)
assert.NotNil(t, err)
tx := &types.CreateTx{
To: "qew",
tx := &rpctypes.CreateTx{
To: "184wj4nsgVxKyz2NhM3Yb5RK5Ap6AFRFq2",
Amount: 10,
Fee: 1,
Note: []byte("12312"),
Note: "12312",
IsWithdraw: false,
IsToken: false,
TokenSymbol: "",
......
......@@ -5,10 +5,10 @@
package rpc_test
import (
"fmt"
"testing"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/rpc/jsonclient"
rpctypes "github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/types"
......@@ -19,16 +19,18 @@ import (
_ "github.com/33cn/chain33/system"
)
func getRPCClient(t *testing.T, mocker *testnode.Chain33Mock) *jsonclient.JSONClient {
jrpcClient := mocker.GetJSONC()
assert.NotNil(t, jrpcClient)
return jrpcClient
}
func TestErrLog(t *testing.T) {
// 启动RPCmocker
mocker := testnode.New("--free--", nil)
defer mocker.Close()
mocker.Listen()
rpcCfg := mocker.GetCfg().RPC
jrpcClient, err := jsonclient.NewJSONClient(fmt.Sprintf("http://%s/", rpcCfg.JrpcBindAddr))
assert.NoError(t, err)
assert.NotNil(t, jrpcClient)
jrpcClient := getRPCClient(t, mocker)
gen := mocker.GetGenesisKey()
//发送交易到区块链
addr1, key1 := util.Genaddress()
......@@ -55,3 +57,43 @@ func TestErrLog(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, string(testResult.Receipt.Logs[0].Log), `"ErrNoBalance"`)
}
func getTx(t *testing.T, hex string) *types.Transaction {
data, err := common.FromHex(hex)
assert.Nil(t, err)
var tx types.Transaction
err = types.Decode(data, &tx)
assert.Nil(t, err)
return &tx
}
func TestSendToExec(t *testing.T) {
mocker := testnode.New("--free--", nil)
defer mocker.Close()
mocker.Listen()
jrpcClient := getRPCClient(t, mocker)
//1. 调用createrawtransaction 创建交易
req := &rpctypes.CreateTx{
To: address.ExecAddress("user.f3d"),
Amount: 10,
Fee: 1,
Note: "12312",
IsWithdraw: false,
IsToken: false,
TokenSymbol: "",
ExecName: "user.f3d",
}
var res string
err := jrpcClient.Call("Chain33.CreateRawTransaction", req, &res)
assert.Nil(t, err)
gen := mocker.GetGenesisKey()
tx := getTx(t, res)
tx.Sign(types.SECP256K1, gen)
reply, err := mocker.GetAPI().SendTx(tx)
assert.Nil(t, err)
_, err = mocker.WaitTx(reply.GetMsg())
assert.Nil(t, err)
block := mocker.GetLastBlock()
balance := mocker.GetExecAccount(block.StateHash, "user.f3d", mocker.GetGenesisAddress()).Balance
assert.Equal(t, int64(10), balance)
}
......@@ -5,6 +5,7 @@
package rpc
import (
"encoding/hex"
"errors"
"testing"
"time"
......@@ -114,10 +115,33 @@ func TestJSONClient_Call(t *testing.T) {
err = jsonClient.Call("Chain33.IsNtpClockSync", &types.ReqNil{}, &retNtp)
assert.Nil(t, err)
assert.True(t, retNtp)
testCreateTxCoins(t, jsonClient)
server.Close()
mock.AssertExpectationsForObjects(t, api)
}
func testCreateTxCoins(t *testing.T, jsonClient *jsonclient.JSONClient) {
req := &rpctypes.CreateTx{
To: "184wj4nsgVxKyz2NhM3Yb5RK5Ap6AFRFq2",
Amount: 10,
Fee: 1,
Note: "12312",
IsWithdraw: false,
IsToken: false,
TokenSymbol: "",
ExecName: types.ExecName("coins"),
}
var res string
err := jsonClient.Call("Chain33.CreateRawTransaction", req, &res)
assert.Nil(t, err)
txbytes, err := hex.DecodeString(res)
assert.Nil(t, err)
var tx types.Transaction
err = types.Decode(txbytes, &tx)
assert.Nil(t, err)
assert.Equal(t, "184wj4nsgVxKyz2NhM3Yb5RK5Ap6AFRFq2", tx.To)
}
func TestGrpc_Call(t *testing.T) {
rpcCfg = new(types.RPC)
rpcCfg.GrpcBindAddr = "127.0.0.1:8101"
......
......@@ -360,3 +360,16 @@ type ExecAccount struct {
type ExecNameParm struct {
ExecName string `json:"execname"`
}
//CreateTx 为了简化Note 的创建过程,在json rpc 中,note 采用string 格式
type CreateTx struct {
To string `json:"to,omitempty"`
Amount int64 `json:"amount,omitempty"`
Fee int64 `json:"fee,omitempty"`
Note string `json:"note,omitempty"`
IsWithdraw bool `json:"isWithdraw,omitempty"`
IsToken bool `json:"isToken,omitempty"`
TokenSymbol string `json:"tokenSymbol,omitempty"`
ExecName string `json:"execName,omitempty"` //TransferToExec and Withdraw 的执行器
Execer string `json:"execer,omitempty"` //执行器名称
}
......@@ -337,6 +337,10 @@ func buildHashList(deltx []*types.Transaction) *types.TxHashList {
//WriteBlock 向blockchain写区块
func (bc *BaseClient) WriteBlock(prev []byte, block *types.Block) error {
//保存block的原始信息用于删除mempool中的错误交易
rawtxs := make([]*types.Transaction, len(block.Txs))
copy(rawtxs, block.Txs)
blockdetail := &types.BlockDetail{Block: block}
msg := bc.client.NewMessage("blockchain", types.EventAddBlockDetail, blockdetail)
bc.client.Send(msg, true)
......@@ -346,7 +350,7 @@ func (bc *BaseClient) WriteBlock(prev []byte, block *types.Block) error {
}
blockdetail = resp.GetData().(*types.BlockDetail)
//从mempool 中删除错误的交易
deltx := diffTx(block.Txs, blockdetail.Block.Txs)
deltx := diffTx(rawtxs, blockdetail.Block.Txs)
if len(deltx) > 0 {
bc.delMempoolTx(deltx)
}
......
......@@ -64,18 +64,19 @@ type Mempool struct {
// Consensus 配置
type Consensus struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
GenesisBlockTime int64 `protobuf:"varint,2,opt,name=genesisBlockTime" json:"genesisBlockTime,omitempty"`
Minerstart bool `protobuf:"varint,3,opt,name=minerstart" json:"minerstart,omitempty"`
Genesis string `protobuf:"bytes,4,opt,name=genesis" json:"genesis,omitempty"`
HotkeyAddr string `protobuf:"bytes,5,opt,name=hotkeyAddr" json:"hotkeyAddr,omitempty"`
ForceMining bool `protobuf:"varint,6,opt,name=forceMining" json:"forceMining,omitempty"`
WriteBlockSeconds int64 `protobuf:"varint,20,opt,name=writeBlockSeconds" json:"writeBlockSeconds,omitempty"`
ParaRemoteGrpcClient string `protobuf:"bytes,22,opt,name=paraRemoteGrpcClient" json:"paraRemoteGrpcClient,omitempty"`
StartHeight int64 `protobuf:"varint,23,opt,name=startHeight" json:"startHeight,omitempty"`
EmptyBlockInterval int64 `protobuf:"varint,24,opt,name=emptyBlockInterval" json:"emptyBlockInterval,omitempty"`
AuthAccount string `protobuf:"bytes,25,opt,name=authAccount" json:"authAccount,omitempty"`
WaitBlocks4CommitMsg int32 `protobuf:"varint,26,opt,name=waitBlocks4CommitMsg" json:"waitBlocks4CommitMsg,omitempty"`
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
GenesisBlockTime int64 `protobuf:"varint,2,opt,name=genesisBlockTime" json:"genesisBlockTime,omitempty"`
Minerstart bool `protobuf:"varint,3,opt,name=minerstart" json:"minerstart,omitempty"`
Genesis string `protobuf:"bytes,4,opt,name=genesis" json:"genesis,omitempty"`
HotkeyAddr string `protobuf:"bytes,5,opt,name=hotkeyAddr" json:"hotkeyAddr,omitempty"`
ForceMining bool `protobuf:"varint,6,opt,name=forceMining" json:"forceMining,omitempty"`
WriteBlockSeconds int64 `protobuf:"varint,20,opt,name=writeBlockSeconds" json:"writeBlockSeconds,omitempty"`
ParaRemoteGrpcClient string `protobuf:"bytes,22,opt,name=paraRemoteGrpcClient" json:"paraRemoteGrpcClient,omitempty"`
StartHeight int64 `protobuf:"varint,23,opt,name=startHeight" json:"startHeight,omitempty"`
EmptyBlockInterval int64 `protobuf:"varint,24,opt,name=emptyBlockInterval" json:"emptyBlockInterval,omitempty"`
AuthAccount string `protobuf:"bytes,25,opt,name=authAccount" json:"authAccount,omitempty"`
WaitBlocks4CommitMsg int32 `protobuf:"varint,26,opt,name=waitBlocks4CommitMsg" json:"waitBlocks4CommitMsg,omitempty"`
SearchHashMatchedBlockDepth int32 `protobuf:"varint,27,opt,name=searchHashMatchedBlockDepth" json:"searchHashMatchedBlockDepth,omitempty"`
}
// Wallet 配置
......
......@@ -225,6 +225,13 @@ func S(key string, value interface{}) {
setChainConfig(key, value)
}
//SetTitleOnlyForTest set title only for test use
func SetTitleOnlyForTest(ti string) {
mu.Lock()
defer mu.Unlock()
title = ti
}
// Init 初始化
func Init(t string, cfg *Config) {
mu.Lock()
......@@ -303,7 +310,6 @@ func SetMinFee(fee int64) {
}
func isPara() bool {
//user.p.guodun.
return strings.Count(title, ".") == 3 && strings.HasPrefix(title, ParaKeyX)
}
......
......@@ -9,6 +9,7 @@ import (
)
var slash = []byte("-")
var sharp = []byte("#")
//Debug 调试开关
var Debug = false
......
......@@ -109,8 +109,8 @@ func CallExecNewTx(execName, action string, param interface{}) ([]byte, error) {
return FormatTxEncode(execName, tx)
}
// CallCreateTx 构造交易信息
func CallCreateTx(execName, action string, param Message) ([]byte, error) {
//CallCreateTransaction 创建一个交易
func CallCreateTransaction(execName, action string, param Message) (*Transaction, error) {
exec := LoadExecutorType(execName)
if exec == nil {
tlog.Error("CallCreateTx", "Error", "exec not found")
......@@ -121,9 +121,13 @@ func CallCreateTx(execName, action string, param Message) ([]byte, error) {
tlog.Error("CallCreateTx", "Error", "param in nil")
return nil, ErrInvalidParam
}
tx, err := exec.Create(action, param)
return exec.Create(action, param)
}
// CallCreateTx 构造交易信息
func CallCreateTx(execName, action string, param Message) ([]byte, error) {
tx, err := CallCreateTransaction(execName, action, param)
if err != nil {
tlog.Error("CallCreateTx", "Error", err)
return nil, err
}
return FormatTxEncode(execName, tx)
......
......@@ -132,5 +132,4 @@ func TestCallCreateTx(t *testing.T) {
assert.Equal(t, tx.Execer, []byte("manage"))
fee, _ = tx.GetRealFee(GInt("MinFee"))
assert.Equal(t, tx.Fee, fee)
}
......@@ -762,6 +762,36 @@ func (_m *Chain33Client) GetSeed(ctx context.Context, in *types.GetSeedByPw, opt
return r0, r1
}
// GetSequenceByHash provides a mock function with given fields: ctx, in, opts
func (_m *Chain33Client) GetSequenceByHash(ctx context.Context, in *types.ReqHash, opts ...grpc.CallOption) (*types.Int64, 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.Int64
if rf, ok := ret.Get(0).(func(context.Context, *types.ReqHash, ...grpc.CallOption) *types.Int64); ok {
r0 = rf(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*types.Int64)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *types.ReqHash, ...grpc.CallOption) error); ok {
r1 = rf(ctx, in, opts...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetTransactionByAddr provides a mock function with given fields: ctx, in, opts
func (_m *Chain33Client) GetTransactionByAddr(ctx context.Context, in *types.ReqAddr, opts ...grpc.CallOption) (*types.ReplyTxInfos, error) {
_va := make([]interface{}, len(opts))
......
......@@ -125,6 +125,9 @@ service chain33 {
//获取指定区间的block加载序列号信息
rpc GetBlockSequences(ReqBlocks) returns (BlockSequences) {}
//get add block's sequence by hash
rpc GetSequenceByHash(ReqHash) returns (Int64) {}
//通过block hash 获取对应的blocks信息
rpc GetBlockByHashes(ReqHashes) returns (BlockDetails) {}
//关闭chain33
......
......@@ -49,6 +49,7 @@ message CreateTx {
bool isToken = 6;
string tokenSymbol = 7;
string execName = 8;
string execer = 9;
}
message CreateTransactionGroup {
......
......@@ -41,6 +41,9 @@ type TxGroup interface {
//ExecName 执行器name
func ExecName(name string) string {
if len(name) > 1 && name[0] == '#' {
return name[1:]
}
if IsParaExecName(name) {
return name
}
......@@ -61,7 +64,7 @@ func IsAllowExecName(name []byte, execer []byte) bool {
return false
}
// name中不允许有 "-"
if bytes.Contains(name, slash) {
if bytes.Contains(name, slash) || bytes.Contains(name, sharp) {
return false
}
if !bytes.Equal(name, execer) && !bytes.Equal(name, GetRealExecName(execer)) {
......
......@@ -5,5 +5,48 @@
package types_test
import (
"testing"
"github.com/33cn/chain33/common/address"
_ "github.com/33cn/chain33/system"
"github.com/33cn/chain33/types"
"github.com/stretchr/testify/assert"
)
//how to create transafer for para
func TestCallCreateTxPara(t *testing.T) {
ti := types.GetTitle()
defer types.SetTitleOnlyForTest(ti)
types.SetTitleOnlyForTest("user.p.sto.")
req := &types.CreateTx{
To: "184wj4nsgVxKyz2NhM3Yb5RK5Ap6AFRFq2",
Amount: 10,
Fee: 1,
Note: []byte("12312"),
IsWithdraw: false,
IsToken: false,
TokenSymbol: "",
ExecName: types.ExecName("coins"),
}
assert.True(t, types.IsPara())
tx, err := types.CallCreateTransaction("coins", "", req)
assert.Nil(t, err)
tx, err = types.FormatTx("coins", tx)
assert.Nil(t, err)
assert.Equal(t, "coins", string(tx.Execer))
assert.Equal(t, address.ExecAddress("coins"), tx.To)
tx, err = types.FormatTx(types.ExecName("coins"), tx)
assert.Nil(t, err)
assert.Equal(t, "user.p.sto.coins", string(tx.Execer))
assert.Equal(t, address.ExecAddress("user.p.sto.coins"), tx.To)
}
func TestExecName(t *testing.T) {
assert.Equal(t, types.ExecName("coins"), "coins")
ti := types.GetTitle()
defer types.SetTitleOnlyForTest(ti)
types.SetTitleOnlyForTest("user.p.sto.")
assert.Equal(t, types.ExecName("coins"), "user.p.sto.coins")
//#在exec前面加一个 # 表示不重写执行器
assert.Equal(t, types.ExecName("#coins"), "coins")
}
......@@ -46,6 +46,12 @@ func TestAllowExecName(t *testing.T) {
isok = IsAllowExecName([]byte("coins"), []byte("user.p.guodun.user.coins"))
assert.Equal(t, isok, true)
isok = IsAllowExecName([]byte("#coins"), []byte("user.p.guodun.user.coins"))
assert.Equal(t, isok, false)
isok = IsAllowExecName([]byte("coins-"), []byte("user.p.guodun.user.coins"))
assert.Equal(t, isok, false)
}
func BenchmarkExecName(b *testing.B) {
......
......@@ -329,6 +329,14 @@ func (mock *Chain33Mock) GetAccount(stateHash []byte, addr string) *types.Accoun
return acc.LoadAccount(addr)
}
//GetExecAccount :get execer account info
func (mock *Chain33Mock) GetExecAccount(stateHash []byte, execer, addr string) *types.Account {
statedb := executor.NewStateDB(mock.client, stateHash, nil, nil)
acc := account.NewCoinsAccount()
acc.SetDB(statedb)
return acc.LoadExecAccount(addr, address.ExecAddress(execer))
}
//GetBlock :
func (mock *Chain33Mock) GetBlock(height int64) *types.Block {
blocks, err := mock.api.GetBlocks(&types.ReqBlocks{Start: height, End: height})
......
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