Commit 814d6a11 authored by harrylee's avatar harrylee Committed by vipwzw

add accountmanager

parent cde06358
all:
chmod +x ./build.sh
./build.sh $(OUT) $(FLAG)
#!/bin/sh
# 官方ci集成脚本
strpwd=$(pwd)
strcmd=${strpwd##*dapp/}
strapp=${strcmd%/cmd*}
OUT_DIR="${1}/$strapp"
#FLAG=$2
mkdir -p "${OUT_DIR}"
cp ./build/* "${OUT_DIR}"
/*Package commands implement dapp client commands*/
package commands
import (
"github.com/spf13/cobra"
)
/*
* 实现合约对应客户端
*/
// Cmd accountmanager client command
func Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "accountmanager",
Short: "accountmanager command",
Args: cobra.MinimumNArgs(1),
}
cmd.AddCommand(
//add sub command
)
return cmd
}
package executor
import (
"fmt"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/client"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
et "github.com/33cn/plugin/plugin/dapp/accountmanager/types"
)
// Action action struct
type Action struct {
statedb dbm.KV
txhash []byte
fromaddr string
blocktime int64
height int64
execaddr string
localDB dbm.KVDB
index int
api client.QueueProtocolAPI
}
func NewAction(e accountmanager, tx *types.Transaction, index int) *Action {
hash := tx.Hash()
fromaddr := tx.From()
return &Action{e.GetStateDB(), hash, fromaddr,
e.GetBlockTime(), e.GetHeight(), dapp.ExecAddress(string(tx.Execer)), e.GetLocalDB(), index, e.GetAPI()}
}
//GetIndex get index
func (a *Action) GetIndex() int64 {
return (a.height*types.MaxTxsPerBlock + int64(a.index)) * 1e4
}
//GetKVSet get kv set
func (a *Action) GetKVSet(account *et.Account) (kvset []*types.KeyValue) {
kvset = append(kvset, &types.KeyValue{Key: calcAccountKey(account.AccountID), Value: types.Encode(account)})
return kvset
}
func (a *Action) Register(payload *et.Register) (*types.Receipt, error) {
var logs []*types.ReceiptLog
account, err := queryMarketDepth(a.localDB, payload.AccountID)
if err == nil && account != nil {
return nil, et.ErrAccountNameExist
}
//TODO 有效期后面统一配置目前暂定五年时间
re := &et.Receipt{
AccountID: payload.AccountID,
Addr: a.fromaddr,
Index: a.GetIndex(),
Status: et.Normal,
CreateTime: a.blocktime,
ExpireTime: a.blocktime + 5*360*24*3600,
}
receiptlog := &types.ReceiptLog{Ty: et.TyRegisterLog, Log: types.Encode(re)}
logs = append(logs, receiptlog)
receipts := &types.Receipt{Ty: types.ExecOk, KV: nil, Logs: logs}
return receipts, nil
}
//为了避免别人恶意重置别人的帐号,这个操作仅有系统管理员有权限去操作
func (a *Action) ReSet(payload *et.Reset) (*types.Receipt, error) {
var logs []*types.ReceiptLog
account, err := queryMarketDepth(a.localDB, payload.AccountID)
if err != nil {
return nil, et.ErrAccountNameNotExist
}
//TODO 重置公钥锁定期暂定15天,后面可以由管理员去配置
re := &et.Receipt{
AccountID: account.AccountID,
PrevAddr: account.Addr,
Addr: payload.Addr,
Index: account.Index,
Status: et.Locked,
CreateTime: account.CreateTime,
ExpireTime: account.ExpireTime,
LockTime: a.blocktime + 15*24*3600,
}
receiptlog := &types.ReceiptLog{Ty: et.TyRegisterLog, Log: types.Encode(re)}
logs = append(logs, receiptlog)
receipts := &types.Receipt{Ty: types.ExecOk, KV: nil, Logs: logs}
return receipts, nil
}
func(a *Action) Transfer(payload *et.Transfer)(*types.Receipt, error){
cfg := a.api.GetConfig()
acc, err := account.NewAccountDB(cfg, payload.Asset.GetExecer(), payload.Asset.GetSymbol(), a.statedb)
if err != nil {
return nil, err
}
}
func queryMarketDepth(localdb dbm.KV, accountName string) (*et.Account, error) {
table := NewAccountTable(localdb)
primaryKey := []byte(fmt.Sprintf("%s", accountName))
row, err := table.GetData(primaryKey)
if err != nil {
return nil, err
}
return row.Data.(*et.Account), nil
}
package executor
import (
log "github.com/33cn/chain33/common/log/log15"
drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
accountmanagertypes "github.com/33cn/plugin/plugin/dapp/accountmanager/types"
)
/*
* 执行器相关定义
* 重载基类相关接口
*/
var (
//日志
elog = log.New("module", "accountmanager.executor")
)
var driverName = accountmanagertypes.AccountmanagerX
// Init register dapp
func Init(name string, cfg *types.Chain33Config, sub []byte) {
drivers.Register(cfg, GetName(), newAccountmanager, cfg.GetDappFork(driverName, "Enable"))
InitExecType()
}
// InitExecType Init Exec Type
func InitExecType() {
ety := types.LoadExecutorType(driverName)
ety.InitFuncList(types.ListMethod(&accountmanager{}))
}
type accountmanager struct {
drivers.DriverBase
}
func newAccountmanager() drivers.Driver {
t := &accountmanager{}
t.SetChild(t)
t.SetExecutorType(types.LoadExecutorType(driverName))
return t
}
// GetName get driver name
func GetName() string {
return newAccountmanager().GetName()
}
func (a *accountmanager) GetDriverName() string {
return driverName
}
// CheckTx 实现自定义检验交易接口,供框架调用
func (a *accountmanager) CheckTx(tx *types.Transaction, index int) error {
// implement code
return nil
}
package executor
import (
"github.com/33cn/chain33/types"
aty "github.com/33cn/plugin/plugin/dapp/accountmanager/types"
)
/*
* 实现交易的链上执行接口
* 关键数据上链(statedb)并生成交易回执(log)
*/
func (a *accountmanager) Exec_Register(payload *aty.Register, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt
//implement code
return receipt, nil
}
func (a *accountmanager) Exec_Reset(payload *aty.Reset, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt
//implement code
return receipt, nil
}
func (a *accountmanager) Exec_Transfer(payload *aty.Transfer, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt
//implement code
return receipt, nil
}
func (a *accountmanager) Exec_Supervise(payload *aty.Supervise, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt
//implement code
return receipt, nil
}
func (a *accountmanager) ExecApply(payload *aty.Apply, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt
//implement code
return receipt, nil
}
\ No newline at end of file
package executor
import (
"github.com/33cn/chain33/types"
)
/*
* 实现区块回退时本地执行的数据清除
*/
// ExecDelLocal 回退自动删除,重写基类
func (a *accountmanager) ExecDelLocal(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
kvs, err := a.DelRollbackKV(tx, tx.Execer)
if err != nil {
return nil, err
}
dbSet := &types.LocalDBSet{}
dbSet.KV = append(dbSet.KV, kvs...)
return dbSet, nil
}
package executor
import (
"github.com/33cn/chain33/types"
accountmanagertypes "github.com/33cn/plugin/plugin/dapp/accountmanager/types"
)
/*
* 实现交易相关数据本地执行,数据不上链
* 非关键数据,本地存储(localDB), 用于辅助查询,效率高
*/
func (a *accountmanager) ExecLocal_Register(payload *accountmanagertypes.Register, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
//implement code
return a.addAutoRollBack(tx, dbSet.KV), nil
}
func (a *accountmanager) ExecLocal_Reset(payload *accountmanagertypes.Reset, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
//implement code
return a.addAutoRollBack(tx, dbSet.KV), nil
}
func (a *accountmanager) ExecLocal_Apply(payload *accountmanagertypes.Apply, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
//implement code
return a.addAutoRollBack(tx, dbSet.KV), nil
}
func (a *accountmanager) ExecLocal_Transfer(payload *accountmanagertypes.Transfer, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
//implement code
return a.addAutoRollBack(tx, dbSet.KV), nil
}
func (a *accountmanager) ExecLocal_Supervise(payload *accountmanagertypes.Supervise, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
//implement code
return a.addAutoRollBack(tx, dbSet.KV), nil
}
//设置自动回滚
func (a *accountmanager) addAutoRollBack(tx *types.Transaction, kv []*types.KeyValue) *types.LocalDBSet {
dbSet := &types.LocalDBSet{}
dbSet.KV = a.AddRollbackKV(tx, tx.Execer, kv)
return dbSet
}
package executor
import (
"fmt"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db/table"
"github.com/33cn/chain33/types"
aty "github.com/33cn/plugin/plugin/dapp/accountmanager/types"
)
/*
* 用户合约存取kv数据时,key值前缀需要满足一定规范
* 即key = keyPrefix + userKey
* 需要字段前缀查询时,使用’-‘作为分割符号
*/
const (
//KeyPrefixStateDB state db key必须前缀
KeyPrefixStateDB = "mavl-accountmanager-"
//KeyPrefixLocalDB local db的key必须前缀
KeyPrefixLocalDB = "LODB-accountmanager"
)
var opt_account = &table.Option{
Prefix: KeyPrefixLocalDB,
Name: "account",
Primary: "accountName",
Index: []string{"status"},
}
//状态数据库中存储具体账户信息
func calcAccountKey(accountName string) []byte {
key := fmt.Sprintf("%s"+"accountName:%s", KeyPrefixStateDB, accountName)
return []byte(key)
}
func NewAccountTable(kvdb db.KV) *table.Table {
rowmeta := NewAccountRow()
table, err := table.NewTable(rowmeta, kvdb, opt_account)
if err != nil {
panic(err)
}
return table
}
//account table meta 结构
type AccountRow struct {
*aty.Account
}
//NewAccountRow 新建一个meta 结构
func NewAccountRow() *AccountRow {
return &AccountRow{Account: &aty.Account{}}
}
//CreateRow 新建数据行(注意index 数据一定也要保存到数据中,不能就保存eventid)
func (m *AccountRow) CreateRow() *table.Row {
return &table.Row{Data: &aty.Account{}}
}
//SetPayload 设置数据
func (m *AccountRow) SetPayload(data types.Message) error {
if txdata, ok := data.(*aty.Account); ok {
m.Account = txdata
return nil
}
return types.ErrTypeAsset
}
//Get 按照indexName 查询 indexValue
func (m *AccountRow) Get(key string) ([]byte, error) {
if key == "accountID" {
return []byte(fmt.Sprintf("%s", m.AccountID)), nil
} else if key == "status" {
return []byte(fmt.Sprintf("%d", m.Status)), nil
}
return nil, types.ErrNotFound
}
package executor
import (
"fmt"
"testing"
)
func Test(t *testing.T){
t.Log(fmt.Sprintf("%-s","aaaa100000b"))
}
\ No newline at end of file
package types
import (
"github.com/33cn/chain33/pluginmgr"
"github.com/33cn/plugin/plugin/dapp/accountmanager/commands"
"github.com/33cn/plugin/plugin/dapp/accountmanager/executor"
"github.com/33cn/plugin/plugin/dapp/accountmanager/rpc"
accountmanagertypes "github.com/33cn/plugin/plugin/dapp/accountmanager/types"
)
/*
* 初始化dapp相关的组件
*/
func init() {
pluginmgr.Register(&pluginmgr.PluginBase{
Name: accountmanagertypes.AccountmanagerX,
ExecName: executor.GetName(),
Exec: executor.Init,
Cmd: commands.Cmd,
RPC: rpc.Init,
})
}
syntax = "proto3";
package types;
message Accountmanager {
}
message AccountmanagerAction {
oneof value {
//注册
Register register = 1;
//重置公钥
Reset reset = 2;
//转账
Transfer transfer = 3;
//监管操作
Supervise supervise = 4;
//申请操作,预留接口
Apply apply = 5;
}
int32 ty = 6;
}
//注册
message Register {
string accountID = 1;
// string addr = 2;
}
//重置公钥
message Reset {
string accountID = 1;
string addr = 2;
}
//用户申请服务
message Apply {
string accountID = 1;
//操作, 0,账户注册,1,账户公钥重置 2,账户延期申请 3,账户注销
int32 op = 2;
}
//资产类型
message asset {
string execer = 1;
string symbol = 2;
}
//合约内部账户之间转账
message Transfer {
//资产类型
asset Asset = 1;
// from账户
string fromAccountID = 2;
// to账户
string toAccountID = 3;
//转账金额
int64 amount = 4;
}
//管理员监管操作
message Supervise {
//账户名单
repeated string accountIDs = 1;
//操作, 1为冻结,2为解冻
int32 op = 2;
}
message Account{
//账户名称
string accountID = 1;
//地址
string addr = 2;
//上一次公钥地址
string prevAddr = 3;
//账户状态 1 正常, 2表示冻结, 3表示锁定 4,过期注销
int32 status = 4;
//注册时间
int64 createTime = 5;
//失效时间
int64 expireTime = 6;
//锁定时间
int64 lockTime = 7;
//索引
int64 index = 8;
}
message Receipt{
//账户名称
string accountID = 1;
//地址
string addr = 2;
//上一次公钥地址
string prevAddr = 3;
//账户状态 1 正常, 2表示冻结, 3表示锁定 4,过期注销
int32 status = 4;
//注册时间
int64 createTime = 5;
//失效时间
int64 expireTime = 6;
//锁定时间
int64 lockTime = 7;
//索引
int64 index = 8;
}
service accountmanager {
}
#!/bin/sh
# proto生成命令,将pb.go文件生成到types/目录下, chain33_path支持引用chain33框架的proto文件
chain33_path=$(go list -f '{{.Dir}}' "github.com/33cn/chain33")
protoc --go_out=plugins=grpc:../types ./*.proto --proto_path=. --proto_path="${chain33_path}/types/proto/"
package rpc
/*
* 实现json rpc和grpc service接口
* json rpc用Jrpc结构作为接收实例
* grpc使用channelClient结构作为接收实例
*/
package rpc
import (
rpctypes "github.com/33cn/chain33/rpc/types"
accountmanagertypes "github.com/33cn/plugin/plugin/dapp/accountmanager/types"
)
/*
* rpc相关结构定义和初始化
*/
// 实现grpc的service接口
type channelClient struct {
rpctypes.ChannelClient
}
// Jrpc 实现json rpc调用实例
type Jrpc struct {
cli *channelClient
}
// Grpc grpc
type Grpc struct {
*channelClient
}
// Init init rpc
func Init(name string, s rpctypes.RPCServer) {
cli := &channelClient{}
grpc := &Grpc{channelClient: cli}
cli.Init(name, s, &Jrpc{cli: cli}, grpc)
//存在grpc service时注册grpc server,需要生成对应的pb.go文件
accountmanagertypes.RegisterAccountmanagerServer(s.GRPC(), grpc)
}
package types
import (
log "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
)
/*
* 交易相关类型定义
* 交易action通常有对应的log结构,用于交易回执日志记录
* 每一种action和log需要用id数值和name名称加以区分
*/
// action类型id和name,这些常量可以自定义修改
const (
TyUnknowAction = iota + 100
TyRegisterAction
TyResetAction
TyTransferAction
TySuperviseAction
TyApplyAction
NameRegisterAction = "Register"
NameResetAction = "Reset"
NameTransferAction = "Transfer"
NameSuperviseAction = "Supervise"
NameApplyAction = "Apply"
)
// log类型id值
const (
TyUnknownLog = iota + 100
TyRegisterLog
TyApplyLog
TyTransferLog
TySuperviseLog
)
//状态
const (
UnknownStatus = iota
Normal
Frozen
Locked
Expired
)
var (
//AccountmanagerX 执行器名称定义
AccountmanagerX = "accountmanager"
//定义actionMap
actionMap = map[string]int32{
NameRegisterAction: TyRegisterAction,
NameResetAction: TyResetAction,
NameApplyAction: TyApplyAction,
NameTransferAction: TyTransferAction,
NameSuperviseAction: TySuperviseAction,
}
//定义log的id和具体log类型及名称,填入具体自定义log类型
logMap = map[int64]*types.LogInfo{
//LogID: {Ty: reflect.TypeOf(LogStruct), Name: LogName},
}
tlog = log.New("module", "accountmanager.types")
)
// init defines a register function
func init() {
types.AllowUserExec = append(types.AllowUserExec, []byte(AccountmanagerX))
//注册合约启用高度
types.RegFork(AccountmanagerX, InitFork)
types.RegExec(AccountmanagerX, InitExecutor)
}
// InitFork defines register fork
func InitFork(cfg *types.Chain33Config) {
cfg.RegisterDappFork(AccountmanagerX, "Enable", 0)
}
// InitExecutor defines register executor
func InitExecutor(cfg *types.Chain33Config) {
types.RegistorExecutor(AccountmanagerX, NewType(cfg))
}
type accountmanagerType struct {
types.ExecTypeBase
}
func NewType(cfg *types.Chain33Config) *accountmanagerType {
c := &accountmanagerType{}
c.SetChild(c)
c.SetConfig(cfg)
return c
}
// GetPayload 获取合约action结构
func (a *accountmanagerType) GetPayload() types.Message {
return &AccountmanagerAction{}
}
// GeTypeMap 获取合约action的id和name信息
func (a *accountmanagerType) GetTypeMap() map[string]int32 {
return actionMap
}
// GetLogMap 获取合约log相关信息
func (a *accountmanagerType) GetLogMap() map[int64]*types.LogInfo {
return logMap
}
This diff is collapsed.
package types
import "fmt"
// some errors definition
var (
ErrAccountNameExist = fmt.Errorf("%s", "The account name has been registered!")
ErrAccountNameNotExist = fmt.Errorf("%s", "The account name is not exist")
)
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