Commit 7d9726f6 authored by 张振华's avatar 张振华

Merge branch 'master' into guess

parents d6f96f30 9ae6ffa1
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''
---
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
package commands
import (
"encoding/json"
"fmt"
"os"
"github.com/33cn/chain33/rpc/jsonclient"
echotypes "github.com/33cn/plugin/plugin/dapp/echo/types/echo"
"github.com/spf13/cobra"
)
// EchoCmd 本执行器的命令行初始化总入口
func EchoCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "echo",
Short: "echo commandline interface",
Args: cobra.MinimumNArgs(1),
}
cmd.AddCommand(
QueryCmd(), // 查询消息记录
// 如果有其它命令,在这里加入
)
return cmd
}
// QueryCmd query 命令
func QueryCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "query",
Short: "query message history",
Run: queryMesage,
}
addPingPangFlags(cmd)
return cmd
}
func addPingPangFlags(cmd *cobra.Command) {
// type参数,指定查询的消息类型,为uint32类型,默认值为1,通过-t参数指定
cmd.Flags().Uint32P("type", "t", 1, "message type, 1:ping 2:pang")
//cmd.MarkFlagRequired("type")
// message参数,执行消息内容,为string类型,默认值为空,通过-m参数制定
cmd.Flags().StringP("message", "m", "", "message content")
cmd.MarkFlagRequired("message")
}
func queryMesage(cmd *cobra.Command, args []string) {
// 这个是命令行的默认参数,可以制定调用哪一个服务地址
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
echoType, _ := cmd.Flags().GetUint32("type")
msg, _ := cmd.Flags().GetString("message")
// 创建RPC客户端,调用我们实现的QueryPing服务接口
client, err := jsonclient.NewJSONClient(rpcLaddr)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
// 初始化查询参数结构
var action = &echotypes.Query{Msg: msg}
if echoType != 1 {
fmt.Fprintln(os.Stderr, "not support")
return
}
var result echotypes.QueryResult
err = client.Call("echo.QueryPing", action, &result)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
data, err := json.MarshalIndent(result, "", " ")
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
fmt.Println(string(data))
}
package doc
// An easy to learn executor example references:
// 1. https://chain.33.cn/document/79#4%20%E4%BA%8C%E6%AC%A1%E5%BC%80%E5%8F%91
// 2. https://chain.33.cn/document/82
package executor
import "github.com/33cn/chain33/types"
// CheckTx 本执行器不做任何校验
func (h *Echo) CheckTx(tx *types.Transaction, index int) error {
return nil
}
package executor
import (
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
echotypes "github.com/33cn/plugin/plugin/dapp/echo/types/echo"
)
var (
// KeyPrefixPing ping 前缀
KeyPrefixPing = "mavl-echo-ping:%s"
// KeyPrefixPang pang 前缀
KeyPrefixPang = "mavl-echo-pang:%s"
// KeyPrefixPingLocal local ping 前缀
KeyPrefixPingLocal = "LODB-echo-ping:%s"
// KeyPrefixPangLocal local pang 前缀
KeyPrefixPangLocal = "LODB-echo-pang:%s"
)
// init 初始化时通过反射获取本执行器的方法列表
func init() {
ety := types.LoadExecutorType(echotypes.EchoX)
ety.InitFuncList(types.ListMethod(&Echo{}))
}
// Init 本执行器的初始化动作,向系统注册本执行器,这里生效高度暂写为0
func Init(name string, sub []byte) {
dapp.Register(echotypes.EchoX, newEcho, 0)
}
// Echo 定义执行器对象
type Echo struct {
dapp.DriverBase
}
// 执行器对象初始化包装逻辑,后面的两步设置子对象和设置执行器类型必不可少
func newEcho() dapp.Driver {
c := &Echo{}
c.SetChild(c)
c.SetExecutorType(types.LoadExecutorType(echotypes.EchoX))
return c
}
// GetDriverName 返回本执行器驱动名称
func (h *Echo) GetDriverName() string {
return echotypes.EchoX
}
package executor
import (
"fmt"
"github.com/33cn/chain33/types"
echotypes "github.com/33cn/plugin/plugin/dapp/echo/types/echo"
)
// Exec_Ping 执行 ping 类型交易
func (h *Echo) Exec_Ping(ping *echotypes.Ping, tx *types.Transaction, index int) (*types.Receipt, error) {
msg := ping.Msg
res := fmt.Sprintf("%s, ping ping ping!", msg)
xx := &echotypes.PingLog{Msg: msg, Echo: res}
logs := []*types.ReceiptLog{{Ty: echotypes.TyLogPing, Log: types.Encode(xx)}}
kv := []*types.KeyValue{{Key: []byte(fmt.Sprintf(KeyPrefixPing, msg)), Value: []byte(res)}}
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
// Exec_Pang 执行 pang 类型交易
func (h *Echo) Exec_Pang(ping *echotypes.Pang, tx *types.Transaction, index int) (*types.Receipt, error) {
msg := ping.Msg
res := fmt.Sprintf("%s, pang pang pang!", msg)
xx := &echotypes.PangLog{Msg: msg, Echo: res}
logs := []*types.ReceiptLog{{Ty: echotypes.TyLogPang, Log: types.Encode(xx)}}
kv := []*types.KeyValue{{Key: []byte(fmt.Sprintf(KeyPrefixPang, msg)), Value: []byte(res)}}
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil
}
package executor
import (
"fmt"
"github.com/33cn/chain33/types"
echotypes "github.com/33cn/plugin/plugin/dapp/echo/types/echo"
)
// ExecDelLocal_Ping 交易执行成功,将本消息对应的数值减1
func (h *Echo) ExecDelLocal_Ping(ping *echotypes.Ping, tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
// 这里简化处理,不做基本的零值及错误检查了
var pingLog echotypes.PingLog
types.Decode(receipt.Logs[0].Log, &pingLog)
localKey := []byte(fmt.Sprintf(KeyPrefixPingLocal, pingLog.Msg))
oldValue, err := h.GetLocalDB().Get(localKey)
if err != nil {
return nil, err
}
types.Decode(oldValue, &pingLog)
if pingLog.Count > 0 {
pingLog.Count--
}
val := types.Encode(&pingLog)
if pingLog.Count == 0 {
val = nil
}
kv := []*types.KeyValue{{Key: localKey, Value: val}}
return &types.LocalDBSet{KV: kv}, nil
}
// ExecDelLocal_Pang 交易执行成功,将本消息对应的数值减1
func (h *Echo) ExecDelLocal_Pang(ping *echotypes.Pang, tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
// 这里简化处理,不做基本的零值及错误检查了
var pangLog echotypes.PangLog
types.Decode(receipt.Logs[0].Log, &pangLog)
localKey := []byte(fmt.Sprintf(KeyPrefixPangLocal, pangLog.Msg))
oldValue, err := h.GetLocalDB().Get(localKey)
if err != nil {
return nil, err
}
types.Decode(oldValue, &pangLog)
if pangLog.Count > 0 {
pangLog.Count--
}
val := types.Encode(&pangLog)
if pangLog.Count == 0 {
val = nil
}
kv := []*types.KeyValue{{Key: localKey, Value: val}}
return &types.LocalDBSet{KV: kv}, nil
}
package executor
import (
"fmt"
"github.com/33cn/chain33/types"
echotypes "github.com/33cn/plugin/plugin/dapp/echo/types/echo"
)
// ExecLocal_Ping 交易执行成功,将本消息对应的数值加1
func (h *Echo) ExecLocal_Ping(ping *echotypes.Ping, tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
// 这里简化处理,不做基本的零值及错误检查了
var pingLog echotypes.PingLog
types.Decode(receipt.Logs[0].Log, &pingLog)
localKey := []byte(fmt.Sprintf(KeyPrefixPingLocal, pingLog.Msg))
oldValue, err := h.GetLocalDB().Get(localKey)
if err != nil && err != types.ErrNotFound {
return nil, err
}
if err == nil {
types.Decode(oldValue, &pingLog)
}
pingLog.Count++
kv := []*types.KeyValue{{Key: localKey, Value: types.Encode(&pingLog)}}
return &types.LocalDBSet{KV: kv}, nil
}
// ExecLocal_Pang 交易执行成功,将本消息对应的数值加1
func (h *Echo) ExecLocal_Pang(ping *echotypes.Pang, tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
// 这里简化处理,不做基本的零值及错误检查了
var pangLog echotypes.PangLog
types.Decode(receipt.Logs[0].Log, &pangLog)
localKey := []byte(fmt.Sprintf(KeyPrefixPangLocal, pangLog.Msg))
oldValue, err := h.GetLocalDB().Get(localKey)
if err != nil && err != types.ErrNotFound {
return nil, err
}
if err == nil {
types.Decode(oldValue, &pangLog)
}
pangLog.Count++
kv := []*types.KeyValue{{Key: localKey, Value: types.Encode(&pangLog)}}
return &types.LocalDBSet{KV: kv}, nil
}
package executor
import (
"fmt"
"github.com/33cn/chain33/types"
echotypes "github.com/33cn/plugin/plugin/dapp/echo/types/echo"
)
// Query_GetPing 查询 ping 次数
func (h *Echo) Query_GetPing(in *echotypes.Query) (types.Message, error) {
var pingLog echotypes.PingLog
localKey := []byte(fmt.Sprintf(KeyPrefixPingLocal, in.Msg))
value, err := h.GetLocalDB().Get(localKey)
if err != nil {
return nil, err
}
types.Decode(value, &pingLog)
res := echotypes.QueryResult{Msg: in.Msg, Count: pingLog.Count}
return &res, nil
}
// Query_GetPang 查询 pang 次数
func (h *Echo) Query_GetPang(in *echotypes.Query) (types.Message, error) {
var pangLog echotypes.PangLog
localKey := []byte(fmt.Sprintf(KeyPrefixPangLocal, in.Msg))
value, err := h.GetLocalDB().Get(localKey)
if err != nil {
return nil, err
}
types.Decode(value, &pangLog)
res := echotypes.QueryResult{Msg: in.Msg, Count: pangLog.Count}
return &res, nil
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package echo
import (
"github.com/33cn/chain33/pluginmgr"
"github.com/33cn/plugin/plugin/dapp/echo/commands"
"github.com/33cn/plugin/plugin/dapp/echo/executor"
"github.com/33cn/plugin/plugin/dapp/echo/rpc"
echotypes "github.com/33cn/plugin/plugin/dapp/echo/types/echo"
)
func init() {
pluginmgr.Register(&pluginmgr.PluginBase{
Name: echotypes.EchoX,
ExecName: echotypes.EchoX,
Exec: executor.Init,
Cmd: commands.EchoCmd,
RPC: rpc.Init,
})
}
syntax = "proto3";
package echo;
// ping操作action
message Ping {
string msg = 1;
}
// pang操作action
message Pang {
string msg = 1;
}
// 本执行器的统一Action结构
message EchoAction {
oneof value {
Ping ping = 1;
Pang pang = 2;
}
int32 ty = 3;
}
// ping操作生成的日志结构
message PingLog {
string msg = 1;
string echo = 2;
int32 count = 3;
}
// pang操作生成的日志结构
message PangLog {
string msg = 1;
string echo = 2;
int32 count = 3;
}
// 查询请求结构
message Query {
string msg = 1;
}
// 查询结果结构
message QueryResult {
string msg = 1;
int32 count = 2;
}
\ No newline at end of file
package rpc
import (
"context"
rpctypes "github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/types"
echotypes "github.com/33cn/plugin/plugin/dapp/echo/types/echo"
)
// Jrpc 对外提供服务的RPC接口总体定义
type Jrpc struct {
cli *channelClient
}
// RPC接口的本地实现
type channelClient struct {
rpctypes.ChannelClient
}
// Init 注册 rpc 接口
func Init(name string, s rpctypes.RPCServer) {
cli := &channelClient{}
// 为了简单起见,这里只注册Jrpc,如果提供grpc的话也在这里注册
cli.Init(name, s, &Jrpc{cli: cli}, nil)
}
// QueryPing 本合约的查询操作可以使用通用的Query接口,这里单独封装rpc的Query接口只是为了说明实现方式
// 接收客户端请求,并调用本地具体实现逻辑,然后返回结果
func (c *Jrpc) QueryPing(param *echotypes.Query, result *interface{}) error {
if param == nil {
return types.ErrInvalidParam
}
// 将具体的接口实现传递给本地逻辑
reply, err := c.cli.QueryPing(context.Background(), param)
if err != nil {
return err
}
*result = reply
return nil
}
// QueryPing 本地具体实现逻辑
func (c *channelClient) QueryPing(ctx context.Context, queryParam *echotypes.Query) (types.Message, error) {
return c.Query(echotypes.EchoX, "GetPing", queryParam)
}
package echo
import (
"encoding/json"
"math/rand"
"strings"
"time"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/types"
)
// CreateTx 创建交易
func (e *Type) CreateTx(action string, message json.RawMessage) (*types.Transaction, error) {
elog.Debug("echo.CreateTx", "action", action)
// 只接受ping/pang两种交易操作
if action == "ping" || action == "pang" {
var param Tx
err := json.Unmarshal(message, &param)
if err != nil {
elog.Error("CreateTx", "Error", err)
return nil, types.ErrInvalidParam
}
return createPingTx(action, &param)
}
return nil, types.ErrNotSupport
}
func createPingTx(op string, parm *Tx) (*types.Transaction, error) {
var action *EchoAction
var err error
if strings.EqualFold(op, "ping") {
action, err = getPingAction(parm)
} else {
action, err = getPangAction(parm)
}
if err != nil {
return nil, err
}
tx := &types.Transaction{
Execer: []byte(types.ExecName(EchoX)),
Payload: types.Encode(action),
Nonce: rand.New(rand.NewSource(time.Now().UnixNano())).Int63(),
To: address.ExecAddress(types.ExecName(EchoX)),
}
return tx, nil
}
func getPingAction(parm *Tx) (*EchoAction, error) {
pingAction := &Ping{Msg: parm.Message}
action := &EchoAction{
Value: &EchoAction_Ping{Ping: pingAction},
Ty: ActionPing,
}
return action, nil
}
func getPangAction(parm *Tx) (*EchoAction, error) {
pangAction := &Pang{Msg: parm.Message}
action := &EchoAction{
Value: &EchoAction_Pang{Pang: pangAction},
Ty: ActionPang,
}
return action, nil
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: echo.proto
/*
Package echo is a generated protocol buffer package.
It is generated from these files:
echo.proto
It has these top-level messages:
Ping
Pang
EchoAction
PingLog
PangLog
Query
QueryResult
*/
package echo
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// ping操作action
type Ping struct {
Msg string `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"`
}
func (m *Ping) Reset() { *m = Ping{} }
func (m *Ping) String() string { return proto.CompactTextString(m) }
func (*Ping) ProtoMessage() {}
func (*Ping) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Ping) GetMsg() string {
if m != nil {
return m.Msg
}
return ""
}
// pang操作action
type Pang struct {
Msg string `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"`
}
func (m *Pang) Reset() { *m = Pang{} }
func (m *Pang) String() string { return proto.CompactTextString(m) }
func (*Pang) ProtoMessage() {}
func (*Pang) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *Pang) GetMsg() string {
if m != nil {
return m.Msg
}
return ""
}
// 本执行器的统一Action结构
type EchoAction struct {
// Types that are valid to be assigned to Value:
// *EchoAction_Ping
// *EchoAction_Pang
Value isEchoAction_Value `protobuf_oneof:"value"`
Ty int32 `protobuf:"varint,3,opt,name=ty" json:"ty,omitempty"`
}
func (m *EchoAction) Reset() { *m = EchoAction{} }
func (m *EchoAction) String() string { return proto.CompactTextString(m) }
func (*EchoAction) ProtoMessage() {}
func (*EchoAction) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
type isEchoAction_Value interface {
isEchoAction_Value()
}
type EchoAction_Ping struct {
Ping *Ping `protobuf:"bytes,1,opt,name=ping,oneof"`
}
type EchoAction_Pang struct {
Pang *Pang `protobuf:"bytes,2,opt,name=pang,oneof"`
}
func (*EchoAction_Ping) isEchoAction_Value() {}
func (*EchoAction_Pang) isEchoAction_Value() {}
func (m *EchoAction) GetValue() isEchoAction_Value {
if m != nil {
return m.Value
}
return nil
}
func (m *EchoAction) GetPing() *Ping {
if x, ok := m.GetValue().(*EchoAction_Ping); ok {
return x.Ping
}
return nil
}
func (m *EchoAction) GetPang() *Pang {
if x, ok := m.GetValue().(*EchoAction_Pang); ok {
return x.Pang
}
return nil
}
func (m *EchoAction) GetTy() int32 {
if m != nil {
return m.Ty
}
return 0
}
// XXX_OneofFuncs is for the internal use of the proto package.
func (*EchoAction) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
return _EchoAction_OneofMarshaler, _EchoAction_OneofUnmarshaler, _EchoAction_OneofSizer, []interface{}{
(*EchoAction_Ping)(nil),
(*EchoAction_Pang)(nil),
}
}
func _EchoAction_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
m := msg.(*EchoAction)
// value
switch x := m.Value.(type) {
case *EchoAction_Ping:
b.EncodeVarint(1<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Ping); err != nil {
return err
}
case *EchoAction_Pang:
b.EncodeVarint(2<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.Pang); err != nil {
return err
}
case nil:
default:
return fmt.Errorf("EchoAction.Value has unexpected type %T", x)
}
return nil
}
func _EchoAction_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
m := msg.(*EchoAction)
switch tag {
case 1: // value.ping
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(Ping)
err := b.DecodeMessage(msg)
m.Value = &EchoAction_Ping{msg}
return true, err
case 2: // value.pang
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(Pang)
err := b.DecodeMessage(msg)
m.Value = &EchoAction_Pang{msg}
return true, err
default:
return false, nil
}
}
func _EchoAction_OneofSizer(msg proto.Message) (n int) {
m := msg.(*EchoAction)
// value
switch x := m.Value.(type) {
case *EchoAction_Ping:
s := proto.Size(x.Ping)
n += proto.SizeVarint(1<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *EchoAction_Pang:
s := proto.Size(x.Pang)
n += proto.SizeVarint(2<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case nil:
default:
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
}
return n
}
// ping操作生成的日志结构
type PingLog struct {
Msg string `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"`
Echo string `protobuf:"bytes,2,opt,name=echo" json:"echo,omitempty"`
Count int32 `protobuf:"varint,3,opt,name=count" json:"count,omitempty"`
}
func (m *PingLog) Reset() { *m = PingLog{} }
func (m *PingLog) String() string { return proto.CompactTextString(m) }
func (*PingLog) ProtoMessage() {}
func (*PingLog) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *PingLog) GetMsg() string {
if m != nil {
return m.Msg
}
return ""
}
func (m *PingLog) GetEcho() string {
if m != nil {
return m.Echo
}
return ""
}
func (m *PingLog) GetCount() int32 {
if m != nil {
return m.Count
}
return 0
}
// pang操作生成的日志结构
type PangLog struct {
Msg string `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"`
Echo string `protobuf:"bytes,2,opt,name=echo" json:"echo,omitempty"`
Count int32 `protobuf:"varint,3,opt,name=count" json:"count,omitempty"`
}
func (m *PangLog) Reset() { *m = PangLog{} }
func (m *PangLog) String() string { return proto.CompactTextString(m) }
func (*PangLog) ProtoMessage() {}
func (*PangLog) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *PangLog) GetMsg() string {
if m != nil {
return m.Msg
}
return ""
}
func (m *PangLog) GetEcho() string {
if m != nil {
return m.Echo
}
return ""
}
func (m *PangLog) GetCount() int32 {
if m != nil {
return m.Count
}
return 0
}
// 查询请求结构
type Query struct {
Msg string `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"`
}
func (m *Query) Reset() { *m = Query{} }
func (m *Query) String() string { return proto.CompactTextString(m) }
func (*Query) ProtoMessage() {}
func (*Query) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *Query) GetMsg() string {
if m != nil {
return m.Msg
}
return ""
}
// 查询结果结构
type QueryResult struct {
Msg string `protobuf:"bytes,1,opt,name=msg" json:"msg,omitempty"`
Count int32 `protobuf:"varint,2,opt,name=count" json:"count,omitempty"`
}
func (m *QueryResult) Reset() { *m = QueryResult{} }
func (m *QueryResult) String() string { return proto.CompactTextString(m) }
func (*QueryResult) ProtoMessage() {}
func (*QueryResult) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func (m *QueryResult) GetMsg() string {
if m != nil {
return m.Msg
}
return ""
}
func (m *QueryResult) GetCount() int32 {
if m != nil {
return m.Count
}
return 0
}
func init() {
proto.RegisterType((*Ping)(nil), "echo.Ping")
proto.RegisterType((*Pang)(nil), "echo.Pang")
proto.RegisterType((*EchoAction)(nil), "echo.EchoAction")
proto.RegisterType((*PingLog)(nil), "echo.PingLog")
proto.RegisterType((*PangLog)(nil), "echo.PangLog")
proto.RegisterType((*Query)(nil), "echo.Query")
proto.RegisterType((*QueryResult)(nil), "echo.QueryResult")
}
func init() { proto.RegisterFile("echo.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 215 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x91, 0x31, 0x4b, 0xc7, 0x30,
0x10, 0xc5, 0x6d, 0xda, 0x58, 0x7a, 0x05, 0x91, 0xe0, 0x10, 0xb7, 0xd2, 0xa9, 0x53, 0x07, 0xc5,
0x0f, 0xa0, 0x50, 0x70, 0x70, 0xd0, 0x7c, 0x83, 0x18, 0x42, 0x1b, 0xa8, 0x49, 0x69, 0x13, 0xa1,
0xdf, 0x5e, 0x72, 0x2d, 0xa2, 0x90, 0xed, 0xbf, 0xbd, 0xf0, 0x1e, 0xbf, 0x97, 0xbb, 0x03, 0xd0,
0x6a, 0x72, 0xfd, 0xb2, 0x3a, 0xef, 0x58, 0x11, 0x75, 0xcb, 0xa1, 0x78, 0x37, 0x76, 0x64, 0xb7,
0x90, 0x7f, 0x6d, 0x23, 0xcf, 0x9a, 0xac, 0xab, 0x44, 0x94, 0xe8, 0xc8, 0xa4, 0x63, 0x00, 0x06,
0x35, 0xb9, 0x67, 0xe5, 0x8d, 0xb3, 0xac, 0x81, 0x62, 0x31, 0xf6, 0x08, 0xd4, 0x0f, 0xd0, 0x63,
0x45, 0x64, 0xbe, 0x5e, 0x09, 0x74, 0x30, 0x21, 0xed, 0xc8, 0xc9, 0xbf, 0x84, 0x3c, 0x13, 0xb1,
0xe3, 0x06, 0x88, 0xdf, 0x79, 0xde, 0x64, 0x1d, 0x15, 0xc4, 0xef, 0x2f, 0x25, 0xd0, 0x6f, 0x39,
0x07, 0xdd, 0x0e, 0x50, 0x46, 0xd4, 0x9b, 0x4b, 0xfc, 0x83, 0x31, 0xc0, 0x19, 0x90, 0x5b, 0x09,
0xd4, 0xec, 0x0e, 0xa8, 0x72, 0xc1, 0xfa, 0x13, 0x76, 0x3c, 0x10, 0x23, 0x2f, 0xc7, 0xdc, 0x03,
0xfd, 0x08, 0x7a, 0xdd, 0x13, 0x3b, 0x79, 0x82, 0x1a, 0x2d, 0xa1, 0xb7, 0x30, 0xfb, 0x44, 0xcb,
0x2f, 0x91, 0xfc, 0x21, 0x7e, 0x5e, 0xe3, 0x2d, 0x1e, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x91,
0xcb, 0x59, 0x09, 0x99, 0x01, 0x00, 0x00,
}
package echo
// Tx echo 交易结构
type Tx struct {
Message string `json:"msg"`
}
package echo
import (
"reflect"
log "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
)
// 定义本执行器支持的Action种类
const (
ActionPing = iota
ActionPang
)
// 定义本执行器生成的log类型
const (
TyLogPing = 100001
TyLogPang = 100002
)
var (
// EchoX 本执行器名称
EchoX = "echo"
// 定义本执行器支持的Action对应关系
actionName = map[string]int32{
"Ping": ActionPing,
"Pang": ActionPang,
}
// 定义本执行器的Log收据解析结构
logInfo = map[int64]*types.LogInfo{
TyLogPing: {Ty: reflect.TypeOf(PingLog{}), Name: "PingLog"},
TyLogPang: {Ty: reflect.TypeOf(PangLog{}), Name: "PangLog"},
}
)
var elog = log.New("module", EchoX)
func init() {
// 将本执行器添加到系统白名单
types.AllowUserExec = append(types.AllowUserExec, []byte(EchoX))
// 向系统注册本执行器类型
types.RegistorExecutor(EchoX, NewType())
}
// Type 定义本执行器类型
type Type struct {
types.ExecTypeBase
}
// NewType 初始化本执行器类型
func NewType() *Type {
c := &Type{}
c.SetChild(c)
return c
}
// GetPayload 返回本执行器的负载类型
func (b *Type) GetPayload() types.Message {
return &EchoAction{}
}
// GetName 返回本执行器名称
func (b *Type) GetName() string {
return EchoX
}
// GetTypeMap 返回本执行器中的action字典,支持双向查找
func (b *Type) GetTypeMap() map[string]int32 {
return actionName
}
// GetLogMap 返回本执行器的日志类型信息,用于rpc解析日志数据
func (b *Type) GetLogMap() map[int64]*types.LogInfo {
return logInfo
}
......@@ -3,6 +3,7 @@ package init
import (
_ "github.com/33cn/plugin/plugin/dapp/blackwhite" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/cert" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/echo" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/evm" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/game" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/guess" //auto gen
......
......@@ -887,7 +887,7 @@ func (m *MultiSig) getMultiSigAccAssets(multiSigAddr string, assets *mty.Assets)
}
var acc1 *types.Account
execaddress := dapp.ExecAddress(m.GetName())
execaddress := dapp.ExecAddress(types.ExecName(m.GetName()))
acc1 = acc.LoadExecAccount(multiSigAddr, execaddress)
return acc1, nil
}
......
......@@ -5,6 +5,7 @@
package executor
import (
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/types"
pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
)
......@@ -18,7 +19,7 @@ func (e *Paracross) ExecDelLocal_Commit(payload *pt.ParacrossCommitAction, tx *t
types.Decode(log.Log, &g)
var r pt.ParacrossTx
r.TxHash = string(tx.Hash())
r.TxHash = common.ToHex(tx.Hash())
set.KV = append(set.KV, &types.KeyValue{Key: calcLocalTxKey(g.Status.Title, g.Status.Height, tx.From()), Value: nil})
} else if log.Ty == pt.TyLogParacrossCommitDone {
var g pt.ReceiptParacrossDone
......@@ -41,7 +42,7 @@ func (e *Paracross) ExecDelLocal_Commit(payload *pt.ParacrossCommitAction, tx *t
types.Decode(log.Log, &g)
var r pt.ParacrossTx
r.TxHash = string(tx.Hash())
r.TxHash = common.ToHex(tx.Hash())
set.KV = append(set.KV, &types.KeyValue{Key: calcLocalTxKey(g.Status.Title, g.Status.Height, tx.From()), Value: nil})
}
}
......
......@@ -7,6 +7,7 @@ package executor
import (
"bytes"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
......@@ -21,7 +22,7 @@ func (e *Paracross) ExecLocal_Commit(payload *pt.ParacrossCommitAction, tx *type
types.Decode(log.Log, &g)
var r pt.ParacrossTx
r.TxHash = string(tx.Hash())
r.TxHash = common.ToHex(tx.Hash())
set.KV = append(set.KV, &types.KeyValue{Key: calcLocalTxKey(g.Status.Title, g.Status.Height, tx.From()), Value: types.Encode(&r)})
} else if log.Ty == pt.TyLogParacrossCommitDone {
var g pt.ReceiptParacrossDone
......@@ -43,7 +44,7 @@ func (e *Paracross) ExecLocal_Commit(payload *pt.ParacrossCommitAction, tx *type
types.Decode(log.Log, &g)
var r pt.ParacrossTx
r.TxHash = string(tx.Hash())
r.TxHash = common.ToHex(tx.Hash())
set.KV = append(set.KV, &types.KeyValue{Key: calcLocalTxKey(g.Status.Title, g.Status.Height, tx.From()), Value: types.Encode(&r)})
}
}
......
......@@ -34,7 +34,7 @@ func CreateRawTx(cmd *cobra.Command, to string, amount float64, note string, isW
transfer.Value = v
transfer.Ty = tokenty.ActionTransfer
} else {
v := &tokenty.TokenAction_Withdraw{Withdraw: &types.AssetsWithdraw{Cointoken: tokenSymbol, Amount: amountInt64, Note: []byte(note)}}
v := &tokenty.TokenAction_Withdraw{Withdraw: &types.AssetsWithdraw{Cointoken: tokenSymbol, Amount: amountInt64, Note: []byte(note), To: to}}
transfer.Value = v
transfer.Ty = tokenty.ActionWithdraw
}
......
......@@ -614,6 +614,7 @@ func (t *trade) loadOrderFromKey(key []byte) *pty.ReplyTradeOrder {
return nil
}
reply.TradedBoardlot = sellOrder.SoldBoardlot
reply.Status = sellOrder.Status
return reply
} else if strings.HasPrefix(string(key), buyIDPrefix) {
txHash := strings.Replace(string(key), buyIDPrefix, "0x", 1)
......@@ -629,6 +630,7 @@ func (t *trade) loadOrderFromKey(key []byte) *pty.ReplyTradeOrder {
return nil
}
reply.TradedBoardlot = buyOrder.BoughtBoardlot
reply.Status = buyOrder.Status
return reply
}
txResult, err := getTx(key, t.GetLocalDB())
......
......@@ -140,7 +140,7 @@ func genSaveBuyLimitKv(buyOrder *pty.BuyLimitOrder) []*types.KeyValue {
kv = saveBuyLimitOrderKeyValue(kv, buyOrder, status)
if pty.TradeOrderStatusBoughtOut == status || pty.TradeOrderStatusBuyRevoked == status {
tradelog.Debug("trade saveBuyLimit ", "remove old status with Buyid", buyOrder.BuyID)
kv = deleteBuyLimitKeyValue(kv, buyOrder, pty.TradeOrderStatusOnSale)
kv = deleteBuyLimitKeyValue(kv, buyOrder, pty.TradeOrderStatusOnBuy)
}
return kv
}
......
......@@ -6,9 +6,9 @@ dist: xenial
notifications:
email: false
jobs:
matrix:
include:
- stage: check_fmt
- name: check_fmt
sudo: require
go:
- "1.9"
......@@ -23,13 +23,13 @@ jobs:
- make checkgofmt && make fmt_go
- make linter
- stage: unit-test
- name: unit-test
go: "1.9.x"
install: skip
script:
- make test
- stage: coverage
- name: coverage
if: branch = master
go:
- "1.9.x"
......@@ -41,7 +41,7 @@ jobs:
after_success:
- bash <(curl -s https://codecov.io/bash)
- stage: deploy
- name: deploy
sudo: required
services:
- docker
......
......@@ -8,7 +8,6 @@ package db
import (
"bytes"
"errors"
"fmt"
"github.com/33cn/chain33/types"
......@@ -16,7 +15,7 @@ import (
)
//ErrNotFoundInDb error
var ErrNotFoundInDb = errors.New("ErrNotFoundInDb")
var ErrNotFoundInDb = types.ErrNotFound
//Lister 列表接口
type Lister interface {
......
......@@ -11,6 +11,7 @@ import (
"fmt"
"github.com/33cn/chain33/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
......@@ -234,3 +235,26 @@ func testDBIteratorDel(t *testing.T, db DB) {
batch.Write()
}
}
func testLevelDBBatch(t *testing.T, db DB) {
batch := db.NewBatch(false)
batch.Set([]byte("hello"), []byte("world"))
err := batch.Write()
assert.Nil(t, err)
v, err := db.Get([]byte("hello"))
assert.Nil(t, err)
assert.Equal(t, v, []byte("world"))
//set and del
batch.Set([]byte("hello1"), []byte("world"))
batch.Set([]byte("hello2"), []byte("world"))
batch.Set([]byte("hello3"), []byte("world"))
batch.Set([]byte("hello4"), []byte("world"))
batch.Set([]byte("hello5"), []byte("world"))
batch.Delete([]byte("hello1"))
err = batch.Write()
assert.Nil(t, err)
v, err = db.Get([]byte("hello1"))
assert.Equal(t, err, types.ErrNotFound)
assert.Nil(t, v)
}
......@@ -43,6 +43,18 @@ func TestGoLevelDBIteratorDel(t *testing.T) {
testDBIteratorDel(t, leveldb)
}
func TestLevelDBBatch(t *testing.T) {
dir, err := ioutil.TempDir("", "goleveldb")
require.NoError(t, err)
t.Log(dir)
leveldb, err := NewGoLevelDB("goleveldb", dir, 128)
require.NoError(t, err)
defer leveldb.Close()
testLevelDBBatch(t, leveldb)
}
// leveldb边界测试
func TestGoLevelDBBoundary(t *testing.T) {
dir, err := ioutil.TempDir("", "goleveldb")
......
......@@ -55,7 +55,6 @@ func (db *ListHelper) List(prefix, key []byte, count, direction int32) (values [
return db.IteratorScanFromFirst(prefix, count)
}
return db.IteratorScanFromLast(prefix, count)
}
if count == 1 && direction == ListSeek {
it := db.db.Iterator(prefix, nil, true)
......
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package table
import (
"math"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types"
)
//Count 计数器
type Count struct {
prefix string
name string
kvdb db.KV
num int64
keydata []byte
}
//NewCount 创建一个计数器
func NewCount(prefix string, name string, kvdb db.KV) *Count {
keydata := []byte(prefix + "#" + name)
return &Count{
prefix: prefix,
name: name,
kvdb: kvdb,
keydata: keydata,
num: math.MinInt64,
}
}
func (c *Count) getKey() []byte {
return c.keydata
}
//Save 保存kv
func (c *Count) Save() (kvs []*types.KeyValue, err error) {
if c.num == math.MinInt64 {
return nil, nil
}
var i types.Int64
i.Data = c.num
item := &types.KeyValue{Key: c.getKey(), Value: types.Encode(&i)}
kvs = append(kvs, item)
return
}
//Get count
func (c *Count) Get() (int64, error) {
if c.num == math.MinInt64 {
data, err := c.kvdb.Get(c.getKey())
if err == types.ErrNotFound {
c.num = 0
} else if err != nil {
return 0, err
}
var num types.Int64
err = types.Decode(data, &num)
if err != nil {
return 0, err
}
c.num = num.Data
}
return c.num, nil
}
//Inc 增加1
func (c *Count) Inc() (num int64, err error) {
c.num, err = c.Get()
if err != nil {
return 0, err
}
c.num++
return c.num, nil
}
//Dec 减少1
func (c *Count) Dec() (num int64, err error) {
c.num, err = c.Get()
if err != nil {
return 0, err
}
c.num--
return c.num, nil
}
//Set 这个操作要谨慎使用
func (c *Count) Set(i int64) {
c.num = i
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package table
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCount(t *testing.T) {
dir, leveldb, kvdb := getdb()
defer dbclose(dir, leveldb)
count := NewCount("prefix", "name#hello", kvdb)
count.Inc()
count.Dec()
count.Inc()
i, err := count.Get()
assert.Nil(t, err)
assert.Equal(t, i, int64(1))
kvs, err := count.Save()
assert.Nil(t, err)
setKV(leveldb, kvs)
count = NewCount("prefix", "name#hello", kvdb)
i, err = count.Get()
assert.Nil(t, err)
assert.Equal(t, i, int64(1))
count.Set(2)
i, err = count.Get()
assert.Nil(t, err)
assert.Equal(t, i, int64(2))
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package table
import "errors"
//table 中的错误处理
var (
ErrEmptyPrimaryKey = errors.New("ErrEmptyPrimaryKey")
ErrPrimaryKey = errors.New("ErrPrimaryKey")
ErrIndexKey = errors.New("ErrIndexKey")
ErrTooManyIndex = errors.New("ErrTooManyIndex")
ErrTablePrefixOrTableName = errors.New("ErrTablePrefixOrTableName")
ErrDupPrimaryKey = errors.New("ErrDupPrimaryKey")
)
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package table
import (
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types"
)
//Query 列表查询结构
type Query struct {
table *Table
kvdb db.KVDB
}
//ListIndex 根据索引查询列表
//index 用哪个index
//prefix 必须要符合的前缀, 可以为空
//primaryKey 开始查询的位置(不包含数据本身)
//count 最多取的数量
//direction 方向
func (query *Query) ListIndex(indexName string, prefix []byte, primaryKey []byte, count, direction int32) (rows []*Row, err error) {
if indexName == "" {
return query.ListPrimary(prefix, primaryKey, count, direction)
}
p := query.table.indexPrefix(indexName)
var k []byte
if len(primaryKey) > 0 {
row, err := query.table.GetData(primaryKey)
if err != nil {
return nil, err
}
key, err := query.table.index(row, indexName)
if err != nil {
return nil, err
}
//如果存在prefix
if prefix != nil {
p2 := commonPrefix(prefix, key)
if len(p2) != len(prefix) {
return nil, types.ErrNotFound
}
p = append(p, p2...)
}
k = query.table.getIndexKey(indexName, key, row.Primary)
} else {
//这个情况下 k == nil
p = append(p, prefix...)
}
values, err := query.kvdb.List(p, k, count, direction)
if err != nil {
return nil, err
}
for _, value := range values {
row, err := query.table.GetData(value)
if err != nil {
return nil, err
}
rows = append(rows, row)
}
return rows, nil
}
//ListPrimary list primary data
func (query *Query) ListPrimary(prefix []byte, primaryKey []byte, count, direction int32) (rows []*Row, err error) {
p := query.table.primaryPrefix()
var k []byte
if primaryKey != nil {
if prefix != nil {
p2 := commonPrefix(prefix, primaryKey)
if len(p2) != len(prefix) {
return nil, types.ErrNotFound
}
p = append(p, p2...)
}
k = append(p, primaryKey...)
} else {
p = append(p, prefix...)
}
values, err := query.kvdb.List(p, k, count, direction)
if err != nil {
return nil, err
}
for _, value := range values {
row, err := query.table.getRow(value)
if err != nil {
return nil, err
}
rows = append(rows, row)
}
return rows, nil
}
func commonPrefix(key1, key2 []byte) []byte {
l1 := len(key1)
l2 := len(key2)
l := min(l1, l2)
for i := 0; i < l; i++ {
if key1[i] != key2[i] {
return key1[:i]
}
}
return key1[0:l]
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
This diff is collapsed.
This diff is collapsed.
......@@ -105,7 +105,7 @@ func CreateRawTx(cmd *cobra.Command, to string, amount float64, note string, isW
transfer.Ty = cty.CoinsActionTransfer
}
} else {
v := &cty.CoinsAction_Withdraw{Withdraw: &types.AssetsWithdraw{Amount: amountInt64, Note: []byte(note), ExecName: execName}}
v := &cty.CoinsAction_Withdraw{Withdraw: &types.AssetsWithdraw{Amount: amountInt64, Note: []byte(note), ExecName: execName, To: to}}
transfer.Value = v
transfer.Ty = cty.CoinsActionWithdraw
}
......
......@@ -97,7 +97,7 @@ func (mem *Mempool) eventProcess() {
func (mem *Mempool) eventTx(msg queue.Message) {
if !mem.getSync() {
msg.Reply(mem.client.NewMessage("", types.EventReply, &types.Reply{Msg: []byte(types.ErrNotSync.Error())}))
mlog.Error("wrong tx", "err", types.ErrNotSync.Error())
mlog.Debug("wrong tx", "err", types.ErrNotSync.Error())
} else {
checkedMsg := mem.checkTxs(msg)
select {
......
......@@ -111,7 +111,9 @@ func CreateTxWithExecer(priv crypto.PrivKey, execer string) *types.Transaction {
tx := &types.Transaction{Execer: []byte(execer), Payload: []byte("none")}
tx.To = address.ExecAddress(execer)
tx, _ = types.FormatTx(execer, tx)
tx.Sign(types.SECP256K1, priv)
if priv != nil {
tx.Sign(types.SECP256K1, priv)
}
return tx
}
......
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