Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
plugin
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
link33
plugin
Commits
65ba0be8
Unverified
Commit
65ba0be8
authored
Mar 13, 2019
by
vipwzw
Committed by
GitHub
Mar 13, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #343 from linj-disanbo/token-mintage
Token mintage
parents
1d82de89
4f20a53d
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1047 additions
and
5 deletions
+1047
-5
token.go
plugin/dapp/token/autotest/token.go
+2
-0
token.toml
plugin/dapp/token/autotest/token.toml
+14
-1
tokenCase.go
plugin/dapp/token/autotest/tokenCase.go
+108
-0
token.go
plugin/dapp/token/commands/token.go
+118
-0
exec.go
plugin/dapp/token/executor/exec.go
+10
-0
exec_del_local.go
plugin/dapp/token/executor/exec_del_local.go
+64
-0
exec_local.go
plugin/dapp/token/executor/exec_local.go
+86
-0
logs.go
plugin/dapp/token/executor/logs.go
+100
-0
query.go
plugin/dapp/token/executor/query.go
+22
-0
token_new_test.go
plugin/dapp/token/executor/token_new_test.go
+73
-0
token_test.go
plugin/dapp/token/executor/token_test.go
+243
-0
tokendb.go
plugin/dapp/token/executor/tokendb.go
+130
-1
transwithdraw.go
plugin/dapp/token/executor/transwithdraw.go
+4
-1
token.proto
plugin/dapp/token/proto/token.proto
+28
-0
rpc.go
plugin/dapp/token/rpc/rpc.go
+26
-0
const.go
plugin/dapp/token/types/const.go
+13
-0
token.pb.go
plugin/dapp/token/types/token.pb.go
+0
-0
types.go
plugin/dapp/token/types/types.go
+4
-0
account_test.go
vendor/github.com/33cn/chain33/account/account_test.go
+1
-0
account.proto
vendor/github.com/33cn/chain33/types/proto/account.proto
+1
-2
No files found.
plugin/dapp/token/autotest/token.go
View file @
65ba0be8
...
...
@@ -18,6 +18,8 @@ type tokenAutoTest struct {
TransferCaseArr
[]
autotest
.
TransferCase
`toml:"TransferCase,omitempty"`
WithdrawCaseArr
[]
autotest
.
WithdrawCase
`toml:"WithdrawCase,omitempty"`
TokenRevokeCaseArr
[]
TokenRevokeCase
`toml:"TokenRevokeCase,omitempty"`
TokenMintCaseArr
[]
TokenMintCase
`toml:"TokenMintCase,omitempty"`
TokenBurnCaseArr
[]
TokenBurnCase
`toml:"TokenBurnCase,omitempty"`
}
func
init
()
{
...
...
plugin/dapp/token/autotest/token.toml
View file @
65ba0be8
...
...
@@ -7,7 +7,7 @@ command = "account import_key -k 0xc21d38be90493512a5c2417d565269a8b23ce8152010e
[[TokenPreCreateCase]]
id
=
"tokenPre"
command
=
"send token precreate -f 0.01 -i testToken -n testToken -s TC -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t 100000 -p 1 -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"
command
=
"send token precreate -
c 1 -
f 0.01 -i testToken -n testToken -s TC -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t 100000 -p 1 -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"
dep
=
[
"transForPrecreate"
,
"import1"
]
[[TokenPreCreateCase]]
...
...
@@ -21,6 +21,19 @@ id = "tokenFinish"
command
=
"send token finish -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -f 0.01 -s TC -k 0xc34b5d9d44ac7b754806f761d3d4d2c4fe5214f6b074c19f069c4f5c2a29c8cc"
dep
=
["tokenPre"]
[[TokenMintCase]]
id
=
"tokenMint"
command
=
"send token mint -a 100 -s TC -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"
dep
=
["tokenFinish"]
amount
=
"100"
checkItem
=
["balance"]
[[TokenBurnCase]]
id
=
"tokenBurn"
command
=
"send token burn -a 50 -s TC -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"
dep
=
["tokenMint"]
amount
=
"50"
checkItem
=
["balance"]
#send to token for precreate
[[TransferCase]]
...
...
plugin/dapp/token/autotest/tokenCase.go
View file @
65ba0be8
...
...
@@ -6,6 +6,8 @@ package autotest
import
(
"github.com/33cn/chain33/cmd/autotest/types"
"strconv"
)
// TokenPreCreateCase token precreatecase command
...
...
@@ -59,3 +61,109 @@ func (testCase *TokenFinishCreateCase) SendCommand(packID string) (types.PackFun
return
types
.
DefaultSend
(
testCase
,
&
TokenFinishCreatePack
{},
packID
)
}
// TokenMintCase token mint case
type
TokenMintCase
struct
{
types
.
BaseCase
Amount
string
`toml:"amount"`
}
// TokenMintPack token mint pack command
type
TokenMintPack
struct
{
types
.
BaseCasePack
}
// SendCommand send command function of tokenfinishcreatecase
func
(
testCase
*
TokenMintCase
)
SendCommand
(
packID
string
)
(
types
.
PackFunc
,
error
)
{
return
types
.
DefaultSend
(
testCase
,
&
TokenMintPack
{},
packID
)
}
// GetCheckHandlerMap get check handle for map
func
(
pack
*
TokenMintPack
)
GetCheckHandlerMap
()
interface
{}
{
funcMap
:=
make
(
types
.
CheckHandlerMapDiscard
,
2
)
funcMap
[
"balance"
]
=
pack
.
checkBalance
return
funcMap
}
func
(
pack
*
TokenMintPack
)
checkBalance
(
txInfo
map
[
string
]
interface
{})
bool
{
logArr
:=
txInfo
[
"receipt"
]
.
(
map
[
string
]
interface
{})[
"logs"
]
.
([]
interface
{})
logTokenBurn
:=
logArr
[
1
]
.
(
map
[
string
]
interface
{})[
"log"
]
.
(
map
[
string
]
interface
{})
logAccBurn
:=
logArr
[
2
]
.
(
map
[
string
]
interface
{})[
"log"
]
.
(
map
[
string
]
interface
{})
interCase
:=
pack
.
TCase
.
(
*
TokenMintCase
)
amount1
,
_
:=
strconv
.
ParseInt
(
interCase
.
Amount
,
10
,
64
)
amount
:=
amount1
*
1e8
pack
.
FLog
.
Info
(
"MintDetails"
,
"TestID"
,
pack
.
PackID
,
"TokenPrev"
,
logTokenBurn
[
"prev"
]
.
(
map
[
string
]
interface
{})[
"total"
]
.
(
string
),
"TokenCurr"
,
logTokenBurn
[
"current"
]
.
(
map
[
string
]
interface
{})[
"total"
]
.
(
string
),
"AccPrev"
,
logAccBurn
[
"prev"
]
.
(
map
[
string
]
interface
{})[
"balance"
]
.
(
string
),
"AccCurr"
,
logAccBurn
[
"current"
]
.
(
map
[
string
]
interface
{})[
"balance"
]
.
(
string
),
"amount"
,
amount1
)
totalCurrent
:=
parseInt64
(
logTokenBurn
[
"current"
]
.
(
map
[
string
]
interface
{})[
"total"
])
totalPrev
:=
parseInt64
(
logTokenBurn
[
"prev"
]
.
(
map
[
string
]
interface
{})[
"total"
])
accCurrent
:=
parseInt64
(
logAccBurn
[
"current"
]
.
(
map
[
string
]
interface
{})[
"balance"
])
accPrev
:=
parseInt64
(
logAccBurn
[
"prev"
]
.
(
map
[
string
]
interface
{})[
"balance"
])
return
totalCurrent
-
amount
==
totalPrev
&&
accCurrent
-
amount
==
accPrev
}
// TokenBurnCase token mint case
type
TokenBurnCase
struct
{
types
.
BaseCase
Amount
string
`toml:"amount"`
}
// TokenBurnPack token mint pack command
type
TokenBurnPack
struct
{
types
.
BaseCasePack
}
// SendCommand send command function
func
(
testCase
*
TokenBurnCase
)
SendCommand
(
packID
string
)
(
types
.
PackFunc
,
error
)
{
return
types
.
DefaultSend
(
testCase
,
&
TokenBurnPack
{},
packID
)
}
// GetCheckHandlerMap get check handle for map
func
(
pack
*
TokenBurnPack
)
GetCheckHandlerMap
()
interface
{}
{
funcMap
:=
make
(
types
.
CheckHandlerMapDiscard
,
2
)
funcMap
[
"balance"
]
=
pack
.
checkBalance
return
funcMap
}
func
(
pack
*
TokenBurnPack
)
checkBalance
(
txInfo
map
[
string
]
interface
{})
bool
{
logArr
:=
txInfo
[
"receipt"
]
.
(
map
[
string
]
interface
{})[
"logs"
]
.
([]
interface
{})
logTokenBurn
:=
logArr
[
1
]
.
(
map
[
string
]
interface
{})[
"log"
]
.
(
map
[
string
]
interface
{})
logAccBurn
:=
logArr
[
2
]
.
(
map
[
string
]
interface
{})[
"log"
]
.
(
map
[
string
]
interface
{})
interCase
:=
pack
.
TCase
.
(
*
TokenBurnCase
)
amount1
,
_
:=
strconv
.
ParseInt
(
interCase
.
Amount
,
10
,
64
)
amount
:=
amount1
*
1e8
pack
.
FLog
.
Info
(
"BurnDetails"
,
"TestID"
,
pack
.
PackID
,
"TokenPrev"
,
logTokenBurn
[
"prev"
]
.
(
map
[
string
]
interface
{})[
"total"
]
.
(
string
),
"TokenCurr"
,
logTokenBurn
[
"current"
]
.
(
map
[
string
]
interface
{})[
"total"
]
.
(
string
),
"AccPrev"
,
logAccBurn
[
"prev"
]
.
(
map
[
string
]
interface
{})[
"balance"
]
.
(
string
),
"AccCurr"
,
logAccBurn
[
"current"
]
.
(
map
[
string
]
interface
{})[
"balance"
]
.
(
string
),
"amount"
,
amount1
)
totalCurrent
:=
parseInt64
(
logTokenBurn
[
"current"
]
.
(
map
[
string
]
interface
{})[
"total"
])
totalPrev
:=
parseInt64
(
logTokenBurn
[
"prev"
]
.
(
map
[
string
]
interface
{})[
"total"
])
accCurrent
:=
parseInt64
(
logAccBurn
[
"current"
]
.
(
map
[
string
]
interface
{})[
"balance"
])
accPrev
:=
parseInt64
(
logAccBurn
[
"prev"
]
.
(
map
[
string
]
interface
{})[
"balance"
])
return
totalCurrent
+
amount
==
totalPrev
&&
accCurrent
+
amount
==
accPrev
}
func
parseInt64
(
s
interface
{})
int64
{
i
,
_
:=
strconv
.
ParseInt
(
s
.
(
string
),
10
,
64
)
return
i
}
plugin/dapp/token/commands/token.go
View file @
65ba0be8
...
...
@@ -42,6 +42,9 @@ func TokenCmd() *cobra.Command {
CreateRawTokenFinishTxCmd
(),
CreateRawTokenRevokeTxCmd
(),
CreateTokenTransferExecCmd
(),
CreateRawTokenMintTxCmd
(),
CreateRawTokenBurnTxCmd
(),
GetTokenLogsCmd
(),
)
return
cmd
...
...
@@ -465,3 +468,118 @@ func tokenRevoke(cmd *cobra.Command, args []string) {
ctx
:=
jsonclient
.
NewRPCCtx
(
rpcLaddr
,
"token.CreateRawTokenRevokeTx"
,
params
,
nil
)
ctx
.
RunWithoutMarshal
()
}
// CreateRawTokenMintTxCmd create raw token mintage transaction
func
CreateRawTokenMintTxCmd
()
*
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
Use
:
"mint"
,
Short
:
"Create a mint token transaction"
,
Run
:
tokenMint
,
}
addTokenMintFlags
(
cmd
)
return
cmd
}
func
addTokenMintFlags
(
cmd
*
cobra
.
Command
)
{
cmd
.
Flags
()
.
StringP
(
"symbol"
,
"s"
,
""
,
"token symbol"
)
cmd
.
MarkFlagRequired
(
"symbol"
)
cmd
.
Flags
()
.
Float64P
(
"amount"
,
"a"
,
0
,
"amount of mintage"
)
cmd
.
MarkFlagRequired
(
"amount"
)
cmd
.
Flags
()
.
Float64P
(
"fee"
,
"f"
,
0
,
"token transaction fee"
)
}
func
tokenMint
(
cmd
*
cobra
.
Command
,
args
[]
string
)
{
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
symbol
,
_
:=
cmd
.
Flags
()
.
GetString
(
"symbol"
)
amount
,
_
:=
cmd
.
Flags
()
.
GetFloat64
(
"amount"
)
params
:=
&
tokenty
.
TokenMint
{
Symbol
:
symbol
,
Amount
:
int64
((
amount
+
0.000001
)
*
1e4
)
*
1e4
,
}
ctx
:=
jsonclient
.
NewRPCCtx
(
rpcLaddr
,
"token.CreateRawTokenMintTx"
,
params
,
nil
)
ctx
.
RunWithoutMarshal
()
}
// CreateRawTokenBurnTxCmd create raw token burn transaction
func
CreateRawTokenBurnTxCmd
()
*
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
Use
:
"burn"
,
Short
:
"Create a burn token transaction"
,
Run
:
tokenBurn
,
}
addTokenBurnFlags
(
cmd
)
return
cmd
}
func
addTokenBurnFlags
(
cmd
*
cobra
.
Command
)
{
cmd
.
Flags
()
.
StringP
(
"symbol"
,
"s"
,
""
,
"token symbol"
)
cmd
.
MarkFlagRequired
(
"symbol"
)
cmd
.
Flags
()
.
Float64P
(
"amount"
,
"a"
,
0
,
"amount of burn"
)
cmd
.
MarkFlagRequired
(
"amount"
)
cmd
.
Flags
()
.
Float64P
(
"fee"
,
"f"
,
0
,
"token transaction fee"
)
}
func
tokenBurn
(
cmd
*
cobra
.
Command
,
args
[]
string
)
{
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
symbol
,
_
:=
cmd
.
Flags
()
.
GetString
(
"symbol"
)
amount
,
_
:=
cmd
.
Flags
()
.
GetFloat64
(
"amount"
)
params
:=
&
tokenty
.
TokenBurn
{
Symbol
:
symbol
,
Amount
:
int64
((
amount
+
0.000001
)
*
1e4
)
*
1e4
,
}
ctx
:=
jsonclient
.
NewRPCCtx
(
rpcLaddr
,
"token.CreateRawTokenBurnTx"
,
params
,
nil
)
ctx
.
RunWithoutMarshal
()
}
// GetTokenLogsCmd get logs of token
func
GetTokenLogsCmd
()
*
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
Use
:
"get_token_logs"
,
Short
:
"Get logs of token"
,
Run
:
getTokenLogs
,
}
getTokenLogsFlags
(
cmd
)
return
cmd
}
func
getTokenLogs
(
cmd
*
cobra
.
Command
,
args
[]
string
)
{
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
paraName
,
_
:=
cmd
.
Flags
()
.
GetString
(
"paraName"
)
symbol
,
_
:=
cmd
.
Flags
()
.
GetString
(
"symbol"
)
var
params
rpctypes
.
Query4Jrpc
params
.
Execer
=
getRealExecName
(
paraName
,
"token"
)
params
.
FuncName
=
"GetTokenHistory"
params
.
Payload
=
types
.
MustPBToJSON
(
&
types
.
ReqString
{
Data
:
symbol
})
rpc
,
err
:=
jsonclient
.
NewJSONClient
(
rpcLaddr
)
if
err
!=
nil
{
fmt
.
Fprintln
(
os
.
Stderr
,
err
)
return
}
var
res
tokenty
.
ReplyTokenLogs
err
=
rpc
.
Call
(
"Chain33.Query"
,
params
,
&
res
)
if
err
!=
nil
{
fmt
.
Fprintln
(
os
.
Stderr
,
err
)
return
}
data
,
err
:=
json
.
MarshalIndent
(
res
,
""
,
" "
)
if
err
!=
nil
{
fmt
.
Fprintln
(
os
.
Stderr
,
err
)
return
}
fmt
.
Println
(
string
(
data
))
}
func
getTokenLogsFlags
(
cmd
*
cobra
.
Command
)
{
cmd
.
Flags
()
.
StringP
(
"symbol"
,
"s"
,
""
,
"token symbol"
)
cmd
.
MarkFlagRequired
(
"symbol"
)
}
plugin/dapp/token/executor/exec.go
View file @
65ba0be8
...
...
@@ -69,3 +69,13 @@ func (t *token) Exec_TransferToExec(payload *types.AssetsTransferToExec, tx *typ
}
return
t
.
ExecTransWithdraw
(
db
,
tx
,
&
tokenAction
,
index
)
}
func
(
t
*
token
)
Exec_TokenMint
(
payload
*
tokenty
.
TokenMint
,
tx
*
types
.
Transaction
,
index
int
)
(
*
types
.
Receipt
,
error
)
{
action
:=
newTokenAction
(
t
,
""
,
tx
)
return
action
.
mint
(
payload
)
}
func
(
t
*
token
)
Exec_TokenBurn
(
payload
*
tokenty
.
TokenBurn
,
tx
*
types
.
Transaction
,
index
int
)
(
*
types
.
Receipt
,
error
)
{
action
:=
newTokenAction
(
t
,
""
,
tx
)
return
action
.
burn
(
payload
)
}
plugin/dapp/token/executor/exec_del_local.go
View file @
65ba0be8
...
...
@@ -5,6 +5,7 @@
package
executor
import
(
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
tokenty
"github.com/33cn/plugin/plugin/dapp/token/types"
)
...
...
@@ -107,6 +108,19 @@ func (t *token) ExecDelLocal_TokenFinishCreate(payload *tokenty.TokenFinishCreat
var
set
[]
*
types
.
KeyValue
set
=
append
(
set
,
&
types
.
KeyValue
{
Key
:
prepareKey
,
Value
:
types
.
Encode
(
localToken
)})
set
=
append
(
set
,
&
types
.
KeyValue
{
Key
:
key
,
Value
:
nil
})
table
:=
NewLogsTable
(
t
.
GetLocalDB
())
txIndex
:=
dapp
.
HeightIndexStr
(
t
.
GetHeight
(),
int64
(
index
))
err
=
table
.
Del
([]
byte
(
txIndex
))
if
err
!=
nil
{
return
nil
,
err
}
kv
,
err
:=
table
.
Save
()
if
err
!=
nil
{
return
nil
,
err
}
set
=
append
(
set
,
kv
...
)
return
&
types
.
LocalDBSet
{
KV
:
set
},
nil
}
...
...
@@ -123,3 +137,53 @@ func (t *token) ExecDelLocal_TokenRevokeCreate(payload *tokenty.TokenRevokeCreat
set
=
append
(
set
,
&
types
.
KeyValue
{
Key
:
prepareKey
,
Value
:
types
.
Encode
(
localToken
)})
return
&
types
.
LocalDBSet
{
KV
:
set
},
nil
}
func
(
t
*
token
)
ExecDelLocal_TokenMint
(
payload
*
tokenty
.
TokenMint
,
tx
*
types
.
Transaction
,
receiptData
*
types
.
ReceiptData
,
index
int
)
(
*
types
.
LocalDBSet
,
error
)
{
localToken
,
err
:=
loadLocalToken
(
payload
.
Symbol
,
tx
.
From
(),
tokenty
.
TokenStatusCreated
,
t
.
GetLocalDB
())
if
err
!=
nil
{
return
nil
,
err
}
localToken
=
resetMint
(
localToken
,
t
.
GetHeight
(),
t
.
GetBlockTime
(),
payload
.
Amount
)
key
:=
calcTokenStatusKeyLocal
(
payload
.
Symbol
,
tx
.
From
(),
tokenty
.
TokenStatusCreated
)
var
set
[]
*
types
.
KeyValue
set
=
append
(
set
,
&
types
.
KeyValue
{
Key
:
key
,
Value
:
types
.
Encode
(
localToken
)})
table
:=
NewLogsTable
(
t
.
GetLocalDB
())
txIndex
:=
dapp
.
HeightIndexStr
(
t
.
GetHeight
(),
int64
(
index
))
err
=
table
.
Del
([]
byte
(
txIndex
))
if
err
!=
nil
{
return
nil
,
err
}
kv
,
err
:=
table
.
Save
()
if
err
!=
nil
{
return
nil
,
err
}
set
=
append
(
set
,
kv
...
)
return
&
types
.
LocalDBSet
{
KV
:
set
},
nil
}
func
(
t
*
token
)
ExecDelLocal_TokenBurn
(
payload
*
tokenty
.
TokenBurn
,
tx
*
types
.
Transaction
,
receiptData
*
types
.
ReceiptData
,
index
int
)
(
*
types
.
LocalDBSet
,
error
)
{
localToken
,
err
:=
loadLocalToken
(
payload
.
Symbol
,
tx
.
From
(),
tokenty
.
TokenStatusCreated
,
t
.
GetLocalDB
())
if
err
!=
nil
{
return
nil
,
err
}
localToken
=
resetBurn
(
localToken
,
t
.
GetHeight
(),
t
.
GetBlockTime
(),
payload
.
Amount
)
key
:=
calcTokenStatusKeyLocal
(
payload
.
Symbol
,
tx
.
From
(),
tokenty
.
TokenStatusCreated
)
var
set
[]
*
types
.
KeyValue
set
=
append
(
set
,
&
types
.
KeyValue
{
Key
:
key
,
Value
:
types
.
Encode
(
localToken
)})
table
:=
NewLogsTable
(
t
.
GetLocalDB
())
txIndex
:=
dapp
.
HeightIndexStr
(
t
.
GetHeight
(),
int64
(
index
))
err
=
table
.
Del
([]
byte
(
txIndex
))
if
err
!=
nil
{
return
nil
,
err
}
kv
,
err
:=
table
.
Save
()
if
err
!=
nil
{
return
nil
,
err
}
set
=
append
(
set
,
kv
...
)
return
&
types
.
LocalDBSet
{
KV
:
set
},
nil
}
plugin/dapp/token/executor/exec_local.go
View file @
65ba0be8
...
...
@@ -5,7 +5,10 @@
package
executor
import
(
"encoding/hex"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
tokenty
"github.com/33cn/plugin/plugin/dapp/token/types"
)
...
...
@@ -107,6 +110,19 @@ func (t *token) ExecLocal_TokenFinishCreate(payload *tokenty.TokenFinishCreate,
set
=
append
(
set
,
&
types
.
KeyValue
{
Key
:
key
,
Value
:
types
.
Encode
(
localToken
)})
kv
:=
AddTokenToAssets
(
payload
.
Owner
,
t
.
GetLocalDB
(),
payload
.
Symbol
)
set
=
append
(
set
,
kv
...
)
table
:=
NewLogsTable
(
t
.
GetLocalDB
())
txIndex
:=
dapp
.
HeightIndexStr
(
t
.
GetHeight
(),
int64
(
index
))
err
=
table
.
Add
(
&
tokenty
.
LocalLogs
{
Symbol
:
payload
.
Symbol
,
TxIndex
:
txIndex
,
ActionType
:
tokenty
.
TokenActionFinishCreate
,
TxHash
:
hex
.
EncodeToString
(
tx
.
Hash
())})
if
err
!=
nil
{
return
nil
,
err
}
kv
,
err
=
table
.
Save
()
if
err
!=
nil
{
return
nil
,
err
}
set
=
append
(
set
,
kv
...
)
return
&
types
.
LocalDBSet
{
KV
:
set
},
nil
}
...
...
@@ -182,6 +198,16 @@ func setRevoked(t *tokenty.LocalToken, height, time int64) *tokenty.LocalToken {
return
t
}
func
setMint
(
t
*
tokenty
.
LocalToken
,
height
,
time
,
amount
int64
)
*
tokenty
.
LocalToken
{
t
.
Total
=
t
.
Total
+
amount
return
t
}
func
setBurn
(
t
*
tokenty
.
LocalToken
,
height
,
time
,
amount
int64
)
*
tokenty
.
LocalToken
{
t
.
Total
=
t
.
Total
-
amount
return
t
}
func
resetCreated
(
t
*
tokenty
.
LocalToken
)
*
tokenty
.
LocalToken
{
t
.
CreatedTime
=
0
t
.
CreatedHeight
=
0
...
...
@@ -195,3 +221,63 @@ func resetRevoked(t *tokenty.LocalToken) *tokenty.LocalToken {
t
.
Status
=
tokenty
.
TokenStatusPreCreated
return
t
}
func
resetMint
(
t
*
tokenty
.
LocalToken
,
height
,
time
,
amount
int64
)
*
tokenty
.
LocalToken
{
t
.
Total
=
t
.
Total
-
amount
return
t
}
func
resetBurn
(
t
*
tokenty
.
LocalToken
,
height
,
time
,
amount
int64
)
*
tokenty
.
LocalToken
{
t
.
Total
=
t
.
Total
+
amount
return
t
}
func
(
t
*
token
)
ExecLocal_TokenMint
(
payload
*
tokenty
.
TokenMint
,
tx
*
types
.
Transaction
,
receiptData
*
types
.
ReceiptData
,
index
int
)
(
*
types
.
LocalDBSet
,
error
)
{
localToken
,
err
:=
loadLocalToken
(
payload
.
Symbol
,
tx
.
From
(),
tokenty
.
TokenStatusCreated
,
t
.
GetLocalDB
())
if
err
!=
nil
{
return
nil
,
err
}
localToken
=
setMint
(
localToken
,
t
.
GetHeight
(),
t
.
GetBlockTime
(),
payload
.
Amount
)
var
set
[]
*
types
.
KeyValue
key
:=
calcTokenStatusKeyLocal
(
payload
.
Symbol
,
tx
.
From
(),
tokenty
.
TokenStatusCreated
)
set
=
append
(
set
,
&
types
.
KeyValue
{
Key
:
key
,
Value
:
types
.
Encode
(
localToken
)})
table
:=
NewLogsTable
(
t
.
GetLocalDB
())
txIndex
:=
dapp
.
HeightIndexStr
(
t
.
GetHeight
(),
int64
(
index
))
err
=
table
.
Add
(
&
tokenty
.
LocalLogs
{
Symbol
:
payload
.
Symbol
,
TxIndex
:
txIndex
,
ActionType
:
tokenty
.
TokenActionMint
,
TxHash
:
"0x"
+
hex
.
EncodeToString
(
tx
.
Hash
())})
if
err
!=
nil
{
return
nil
,
err
}
kv
,
err
:=
table
.
Save
()
if
err
!=
nil
{
return
nil
,
err
}
set
=
append
(
set
,
kv
...
)
return
&
types
.
LocalDBSet
{
KV
:
set
},
nil
}
func
(
t
*
token
)
ExecLocal_TokenBurn
(
payload
*
tokenty
.
TokenBurn
,
tx
*
types
.
Transaction
,
receiptData
*
types
.
ReceiptData
,
index
int
)
(
*
types
.
LocalDBSet
,
error
)
{
localToken
,
err
:=
loadLocalToken
(
payload
.
Symbol
,
tx
.
From
(),
tokenty
.
TokenStatusCreated
,
t
.
GetLocalDB
())
if
err
!=
nil
{
return
nil
,
err
}
localToken
=
setBurn
(
localToken
,
t
.
GetHeight
(),
t
.
GetBlockTime
(),
payload
.
Amount
)
var
set
[]
*
types
.
KeyValue
key
:=
calcTokenStatusKeyLocal
(
payload
.
Symbol
,
tx
.
From
(),
tokenty
.
TokenStatusCreated
)
set
=
append
(
set
,
&
types
.
KeyValue
{
Key
:
key
,
Value
:
types
.
Encode
(
localToken
)})
table
:=
NewLogsTable
(
t
.
GetLocalDB
())
txIndex
:=
dapp
.
HeightIndexStr
(
t
.
GetHeight
(),
int64
(
index
))
err
=
table
.
Add
(
&
tokenty
.
LocalLogs
{
Symbol
:
payload
.
Symbol
,
TxIndex
:
txIndex
,
ActionType
:
tokenty
.
TokenActionBurn
,
TxHash
:
"0x"
+
hex
.
EncodeToString
(
tx
.
Hash
())})
if
err
!=
nil
{
return
nil
,
err
}
kv
,
err
:=
table
.
Save
()
if
err
!=
nil
{
return
nil
,
err
}
set
=
append
(
set
,
kv
...
)
return
&
types
.
LocalDBSet
{
KV
:
set
},
nil
}
plugin/dapp/token/executor/logs.go
0 → 100644
View file @
65ba0be8
// 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
executor
// 记录token 的更改记录,
// 包含创建完成, 铸币, 以后可能包含燃烧等
import
(
dbm
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db/table"
"github.com/33cn/chain33/types"
pty
"github.com/33cn/plugin/plugin/dapp/token/types"
)
var
opt_logs_table
=
&
table
.
Option
{
Prefix
:
"LODB-token"
,
Name
:
"logs"
,
Primary
:
"txIndex"
,
Index
:
[]
string
{
"symbol"
,
},
}
// LogsRow row
type
LogsRow
struct
{
*
pty
.
LocalLogs
}
// NewOrderRow create row
func
NewOrderRow
()
*
LogsRow
{
return
&
LogsRow
{
LocalLogs
:
nil
}
}
// CreateRow create row
func
(
r
*
LogsRow
)
CreateRow
()
*
table
.
Row
{
return
&
table
.
Row
{
Data
:
&
pty
.
LocalLogs
{}}
}
// SetPayload set payload
func
(
r
*
LogsRow
)
SetPayload
(
data
types
.
Message
)
error
{
if
d
,
ok
:=
data
.
(
*
pty
.
LocalLogs
);
ok
{
r
.
LocalLogs
=
d
return
nil
}
return
types
.
ErrTypeAsset
}
// Get get index key
func
(
r
*
LogsRow
)
Get
(
key
string
)
([]
byte
,
error
)
{
switch
key
{
case
"txIndex"
:
return
[]
byte
(
r
.
TxIndex
),
nil
case
"symbol"
:
return
[]
byte
(
r
.
Symbol
),
nil
default
:
return
nil
,
types
.
ErrNotFound
}
}
// NewLogsTable create table
func
NewLogsTable
(
kvdb
dbm
.
KV
)
*
table
.
Table
{
rowMeta
:=
NewOrderRow
()
err
:=
rowMeta
.
SetPayload
(
&
pty
.
LocalLogs
{})
if
err
!=
nil
{
panic
(
err
)
}
t
,
err
:=
table
.
NewTable
(
rowMeta
,
kvdb
,
opt_logs_table
)
if
err
!=
nil
{
panic
(
err
)
}
return
t
}
func
list
(
db
dbm
.
KVDB
,
indexName
string
,
data
*
pty
.
LocalLogs
,
count
,
direction
int32
)
([]
*
table
.
Row
,
error
)
{
query
:=
NewLogsTable
(
db
)
.
GetQuery
(
db
)
var
primary
[]
byte
if
len
(
data
.
TxIndex
)
>
0
{
primary
=
[]
byte
(
data
.
TxIndex
)
}
cur
:=
&
LogsRow
{
LocalLogs
:
data
}
index
,
err
:=
cur
.
Get
(
indexName
)
if
err
!=
nil
{
tokenlog
.
Error
(
"query List failed"
,
"key"
,
string
(
primary
),
"param"
,
data
,
"err"
,
err
)
return
nil
,
err
}
tokenlog
.
Debug
(
"query List dbg"
,
"indexName"
,
indexName
,
"index"
,
string
(
index
),
"primary"
,
primary
,
"count"
,
count
,
"direction"
,
direction
)
rows
,
err
:=
query
.
ListIndex
(
indexName
,
index
,
primary
,
count
,
direction
)
if
err
!=
nil
{
tokenlog
.
Error
(
"query List failed"
,
"key"
,
string
(
primary
),
"param"
,
data
,
"err"
,
err
)
return
nil
,
err
}
if
len
(
rows
)
==
0
{
return
nil
,
types
.
ErrNotFound
}
return
rows
,
nil
}
plugin/dapp/token/executor/query.go
View file @
65ba0be8
...
...
@@ -69,3 +69,25 @@ func (t *token) Query_GetTxByToken(in *tokenty.ReqTokenTx) (types.Message, error
}
return
t
.
getTxByToken
(
in
)
}
// Query_GetTokenHistory 获取token 的变更历史
func
(
t
*
token
)
Query_GetTokenHistory
(
in
*
types
.
ReqString
)
(
types
.
Message
,
error
)
{
if
in
==
nil
{
return
nil
,
types
.
ErrInvalidParam
}
rows
,
err
:=
list
(
t
.
GetLocalDB
(),
"symbol"
,
&
tokenty
.
LocalLogs
{
Symbol
:
in
.
Data
},
-
1
,
0
)
if
err
!=
nil
{
tokenlog
.
Error
(
"Query_GetTokenHistory"
,
"err"
,
err
)
return
nil
,
err
}
var
replys
tokenty
.
ReplyTokenLogs
for
_
,
row
:=
range
rows
{
o
,
ok
:=
row
.
Data
.
(
*
tokenty
.
LocalLogs
)
if
!
ok
{
tokenlog
.
Error
(
"Query_GetTokenHistory"
,
"err"
,
"bad row type"
)
return
nil
,
types
.
ErrTypeAsset
}
replys
.
Logs
=
append
(
replys
.
Logs
,
o
)
}
return
&
replys
,
nil
}
plugin/dapp/token/executor/token_new_test.go
View file @
65ba0be8
...
...
@@ -157,6 +157,7 @@ func TestPrecreate(t *testing.T) {
Total
:
tokenAmount
,
Price
:
tokenPrice
,
Owner
:
addr
,
Category
:
pty
.
CategoryMintBurnSupport
,
}
precreate
:=
&
pty
.
TokenAction
{
Ty
:
pty
.
TokenActionPreCreate
,
...
...
@@ -312,6 +313,78 @@ func TestQueryAsset(t *testing.T) {
}
func
TestTokenMint
(
t
*
testing
.
T
)
{
if
!
isMainNetTest
{
return
}
fmt
.
Println
(
"TestTokenMint start"
)
defer
fmt
.
Println
(
"TestTokenMint end"
)
v
:=
&
pty
.
TokenAction_TokenMint
{
TokenMint
:
&
pty
.
TokenMint
{
Symbol
:
tokenSym
,
Amount
:
transAmount
}}
transfer
:=
&
pty
.
TokenAction
{
Value
:
v
,
Ty
:
pty
.
ActionTransfer
}
tx
:=
&
types
.
Transaction
{
Execer
:
[]
byte
(
execName
),
Payload
:
types
.
Encode
(
transfer
),
Fee
:
fee
,
To
:
addrexec
}
tx
.
Nonce
=
r
.
Int63
()
tx
.
Sign
(
types
.
SECP256K1
,
privkey
)
reply
,
err
:=
mainClient
.
SendTransaction
(
context
.
Background
(),
tx
)
if
err
!=
nil
{
fmt
.
Println
(
"err"
,
err
)
t
.
Error
(
err
)
return
}
if
!
reply
.
IsOk
{
fmt
.
Println
(
"err = "
,
reply
.
GetMsg
())
t
.
Error
(
ErrTest
)
return
}
if
!
waitTx
(
tx
.
Hash
())
{
t
.
Error
(
ErrTest
)
return
}
}
func
TestQueryTokenLogs
(
t
*
testing
.
T
)
{
if
!
isParaNetTest
{
return
}
fmt
.
Println
(
"TestQueryTokenLogs start"
)
defer
fmt
.
Println
(
"TestQueryTokenLogs end"
)
var
req
types
.
ChainExecutor
req
.
Driver
=
execName
req
.
FuncName
=
"GetTokenHistory"
req
.
Param
=
types
.
Encode
(
&
types
.
ReqString
{
Data
:
tokenSym
})
reply
,
err
:=
paraClient
.
QueryChain
(
context
.
Background
(),
&
req
)
if
err
!=
nil
{
fmt
.
Println
(
err
)
t
.
Error
(
err
)
return
}
if
!
reply
.
IsOk
{
fmt
.
Println
(
"Query reply err"
)
t
.
Error
(
ErrTest
)
return
}
var
res
pty
.
ReplyTokenLogs
err
=
types
.
Decode
(
reply
.
Msg
,
&
res
)
if
err
!=
nil
{
t
.
Error
(
err
)
return
}
assert
.
Equal
(
t
,
2
,
len
(
res
.
Logs
))
for
_
,
l
:=
range
res
.
Logs
{
fmt
.
Println
(
l
.
Symbol
)
fmt
.
Println
(
l
.
TxHash
)
fmt
.
Println
(
l
.
TxIndex
)
fmt
.
Println
(
l
.
ActionType
)
}
}
//***************************************************
//**************common actions for Test**************
//***************************************************
...
...
plugin/dapp/token/executor/token_test.go
0 → 100644
View file @
65ba0be8
package
executor
import
(
"testing"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/crypto"
dbm
"github.com/33cn/chain33/common/db"
pty
"github.com/33cn/plugin/plugin/dapp/token/types"
"github.com/stretchr/testify/assert"
//"github.com/33cn/chain33/types/jsonpb"
)
type
execEnv
struct
{
blockTime
int64
blockHeight
int64
difficulty
uint64
}
var
(
Symbol
=
"TEST"
AssetExecToken
=
"token"
AssetExecPara
=
"paracross"
PrivKeyA
=
"0x6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b"
// 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4
PrivKeyB
=
"0x19c069234f9d3e61135fefbeb7791b149cdf6af536f26bebb310d4cd22c3fee4"
// 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR
PrivKeyC
=
"0x7a80a1f75d7360c6123c32a78ecf978c1ac55636f87892df38d8b85a9aeff115"
// 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k
PrivKeyD
=
"0xcacb1f5d51700aea07fca2246ab43b0917d70405c65edea9b5063d72eb5c6b71"
// 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs
Nodes
=
[][]
byte
{
[]
byte
(
"1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"
),
[]
byte
(
"1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR"
),
[]
byte
(
"1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"
),
[]
byte
(
"1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs"
),
}
)
func
TestToken
(
t
*
testing
.
T
)
{
types
.
SetTitleOnlyForTest
(
"chain33"
)
tokenTotal
:=
int64
(
10000
*
1e8
)
tokenBurn
:=
int64
(
10
*
1e8
)
tokenMint
:=
int64
(
20
*
1e8
)
total
:=
int64
(
100000
)
accountA
:=
types
.
Account
{
Balance
:
total
,
Frozen
:
0
,
Addr
:
string
(
Nodes
[
0
]),
}
accountB
:=
types
.
Account
{
Balance
:
total
,
Frozen
:
0
,
Addr
:
string
(
Nodes
[
1
]),
}
execAddr
:=
address
.
ExecAddress
(
pty
.
TokenX
)
stateDB
,
_
:=
dbm
.
NewGoMemDB
(
"1"
,
"2"
,
100
)
_
,
_
,
kvdb
:=
util
.
CreateTestDB
()
accA
,
_
:=
account
.
NewAccountDB
(
AssetExecPara
,
Symbol
,
stateDB
)
accA
.
SaveExecAccount
(
execAddr
,
&
accountA
)
accB
,
_
:=
account
.
NewAccountDB
(
AssetExecPara
,
Symbol
,
stateDB
)
accB
.
SaveExecAccount
(
execAddr
,
&
accountB
)
env
:=
execEnv
{
10
,
types
.
GetDappFork
(
pty
.
TokenX
,
pty
.
ForkTokenSymbolWithNumberX
),
1539918074
,
}
// set config key
item
:=
&
types
.
ConfigItem
{
Key
:
"mavl-manage-token-blacklist"
,
Value
:
&
types
.
ConfigItem_Arr
{
Arr
:
&
types
.
ArrayConfig
{
Value
:
[]
string
{
"bty"
}},
},
}
stateDB
.
Set
([]
byte
(
item
.
Key
),
types
.
Encode
(
item
))
item2
:=
&
types
.
ConfigItem
{
Key
:
"mavl-manage-token-finisher"
,
Value
:
&
types
.
ConfigItem_Arr
{
Arr
:
&
types
.
ArrayConfig
{
Value
:
[]
string
{
string
(
Nodes
[
0
])}},
},
}
stateDB
.
Set
([]
byte
(
item2
.
Key
),
types
.
Encode
(
item2
))
// create token
// 创建
//ty := pty.TokenType{}
p1
:=
&
pty
.
TokenPreCreate
{
Name
:
Symbol
,
Symbol
:
Symbol
,
Introduction
:
Symbol
,
Total
:
tokenTotal
,
Price
:
0
,
Owner
:
string
(
Nodes
[
0
]),
Category
:
pty
.
CategoryMintBurnSupport
,
}
//v, _ := types.PBToJSON(p1)
createTx
,
err
:=
types
.
CallCreateTransaction
(
pty
.
TokenX
,
"TokenPreCreate"
,
p1
)
if
err
!=
nil
{
t
.
Error
(
"RPC_Default_Process"
,
"err"
,
err
)
}
createTx
,
err
=
signTx
(
createTx
,
PrivKeyA
)
if
err
!=
nil
{
t
.
Error
(
"RPC_Default_Process sign"
,
"err"
,
err
)
}
exec
:=
newToken
()
exec
.
SetStateDB
(
stateDB
)
exec
.
SetLocalDB
(
kvdb
)
exec
.
SetEnv
(
env
.
blockHeight
,
env
.
blockTime
,
env
.
difficulty
)
receipt
,
err
:=
exec
.
Exec
(
createTx
,
int
(
1
))
assert
.
Nil
(
t
,
err
)
assert
.
NotNil
(
t
,
receipt
)
t
.
Log
(
receipt
)
for
_
,
kv
:=
range
receipt
.
KV
{
stateDB
.
Set
(
kv
.
Key
,
kv
.
Value
)
}
receiptDate
:=
&
types
.
ReceiptData
{
Ty
:
receipt
.
Ty
,
Logs
:
receipt
.
Logs
}
set
,
err
:=
exec
.
ExecLocal
(
createTx
,
receiptDate
,
int
(
1
))
assert
.
Nil
(
t
,
err
)
assert
.
NotNil
(
t
,
set
)
p2
:=
&
pty
.
TokenFinishCreate
{
Symbol
:
Symbol
,
Owner
:
string
(
Nodes
[
0
]),
}
//v, _ := types.PBToJSON(p1)
createTx2
,
err
:=
types
.
CallCreateTransaction
(
pty
.
TokenX
,
"TokenFinishCreate"
,
p2
)
if
err
!=
nil
{
t
.
Error
(
"RPC_Default_Process"
,
"err"
,
err
)
}
createTx2
,
err
=
signTx
(
createTx2
,
PrivKeyA
)
if
err
!=
nil
{
t
.
Error
(
"RPC_Default_Process sign"
,
"err"
,
err
)
}
exec
.
SetEnv
(
env
.
blockHeight
+
1
,
env
.
blockTime
+
1
,
env
.
difficulty
)
receipt
,
err
=
exec
.
Exec
(
createTx2
,
int
(
1
))
assert
.
Nil
(
t
,
err
)
assert
.
NotNil
(
t
,
receipt
)
//t.Log(receipt)
for
_
,
kv
:=
range
receipt
.
KV
{
stateDB
.
Set
(
kv
.
Key
,
kv
.
Value
)
}
accDB
,
_
:=
account
.
NewAccountDB
(
pty
.
TokenX
,
Symbol
,
stateDB
)
accChcek
:=
accDB
.
LoadAccount
(
string
(
Nodes
[
0
]))
assert
.
Equal
(
t
,
tokenTotal
,
accChcek
.
Balance
)
receiptDate
=
&
types
.
ReceiptData
{
Ty
:
receipt
.
Ty
,
Logs
:
receipt
.
Logs
}
set
,
err
=
exec
.
ExecLocal
(
createTx2
,
receiptDate
,
int
(
1
))
assert
.
Nil
(
t
,
err
)
assert
.
NotNil
(
t
,
set
)
// mint burn
p3
:=
&
pty
.
TokenMint
{
Symbol
:
Symbol
,
Amount
:
tokenMint
,
}
//v, _ := types.PBToJSON(p1)
createTx3
,
err
:=
types
.
CallCreateTransaction
(
pty
.
TokenX
,
"TokenMint"
,
p3
)
if
err
!=
nil
{
t
.
Error
(
"RPC_Default_Process"
,
"err"
,
err
)
}
createTx3
,
err
=
signTx
(
createTx3
,
PrivKeyA
)
if
err
!=
nil
{
t
.
Error
(
"RPC_Default_Process sign"
,
"err"
,
err
)
}
exec
.
SetEnv
(
env
.
blockHeight
+
2
,
env
.
blockTime
+
2
,
env
.
difficulty
)
receipt
,
err
=
exec
.
Exec
(
createTx3
,
int
(
1
))
assert
.
Nil
(
t
,
err
)
assert
.
NotNil
(
t
,
receipt
)
//t.Log(receipt)
for
_
,
kv
:=
range
receipt
.
KV
{
stateDB
.
Set
(
kv
.
Key
,
kv
.
Value
)
}
accChcek
=
accDB
.
LoadAccount
(
string
(
Nodes
[
0
]))
assert
.
Equal
(
t
,
tokenTotal
+
tokenMint
,
accChcek
.
Balance
)
receiptDate
=
&
types
.
ReceiptData
{
Ty
:
receipt
.
Ty
,
Logs
:
receipt
.
Logs
}
set
,
err
=
exec
.
ExecLocal
(
createTx3
,
receiptDate
,
int
(
1
))
assert
.
Nil
(
t
,
err
)
assert
.
NotNil
(
t
,
set
)
p4
:=
&
pty
.
TokenBurn
{
Symbol
:
Symbol
,
Amount
:
tokenBurn
,
}
//v, _ := types.PBToJSON(p1)
createTx4
,
err
:=
types
.
CallCreateTransaction
(
pty
.
TokenX
,
"TokenBurn"
,
p4
)
if
err
!=
nil
{
t
.
Error
(
"RPC_Default_Process"
,
"err"
,
err
)
}
createTx4
,
err
=
signTx
(
createTx4
,
PrivKeyA
)
if
err
!=
nil
{
t
.
Error
(
"RPC_Default_Process sign"
,
"err"
,
err
)
}
exec
.
SetEnv
(
env
.
blockHeight
+
1
,
env
.
blockTime
+
1
,
env
.
difficulty
)
receipt
,
err
=
exec
.
Exec
(
createTx4
,
int
(
1
))
assert
.
Nil
(
t
,
err
)
assert
.
NotNil
(
t
,
receipt
)
//t.Log(receipt)
for
_
,
kv
:=
range
receipt
.
KV
{
stateDB
.
Set
(
kv
.
Key
,
kv
.
Value
)
}
accChcek
=
accDB
.
LoadAccount
(
string
(
Nodes
[
0
]))
assert
.
Equal
(
t
,
tokenTotal
+
tokenMint
-
tokenBurn
,
accChcek
.
Balance
)
receiptDate
=
&
types
.
ReceiptData
{
Ty
:
receipt
.
Ty
,
Logs
:
receipt
.
Logs
}
set
,
err
=
exec
.
ExecLocal
(
createTx4
,
receiptDate
,
int
(
1
))
assert
.
Nil
(
t
,
err
)
assert
.
NotNil
(
t
,
set
)
}
func
signTx
(
tx
*
types
.
Transaction
,
hexPrivKey
string
)
(
*
types
.
Transaction
,
error
)
{
signType
:=
types
.
SECP256K1
c
,
err
:=
crypto
.
New
(
types
.
GetSignName
(
pty
.
TokenX
,
signType
))
if
err
!=
nil
{
return
tx
,
err
}
bytes
,
err
:=
common
.
FromHex
(
hexPrivKey
[
:
])
if
err
!=
nil
{
return
tx
,
err
}
privKey
,
err
:=
c
.
PrivKeyFromBytes
(
bytes
)
if
err
!=
nil
{
return
tx
,
err
}
tx
.
Sign
(
int32
(
signType
),
privKey
)
return
tx
,
nil
}
plugin/dapp/token/executor/tokendb.go
View file @
65ba0be8
...
...
@@ -40,7 +40,10 @@ func newTokenDB(preCreate *pty.TokenPreCreate, creator string, height int64) *to
func
(
t
*
tokenDB
)
save
(
db
dbm
.
KV
,
key
[]
byte
)
{
set
:=
t
.
getKVSet
(
key
)
for
i
:=
0
;
i
<
len
(
set
);
i
++
{
db
.
Set
(
set
[
i
]
.
GetKey
(),
set
[
i
]
.
Value
)
err
:=
db
.
Set
(
set
[
i
]
.
GetKey
(),
set
[
i
]
.
Value
)
if
err
!=
nil
{
panic
(
err
)
}
}
}
...
...
@@ -59,6 +62,48 @@ func (t *tokenDB) getKVSet(key []byte) (kvset []*types.KeyValue) {
return
kvset
}
func
loadTokenDB
(
db
dbm
.
KV
,
symbol
string
)
(
*
tokenDB
,
error
)
{
token
,
err
:=
db
.
Get
(
calcTokenKey
(
symbol
))
if
err
!=
nil
{
tokenlog
.
Error
(
"tokendb load "
,
"Can't get token form db for token"
,
symbol
)
return
nil
,
pty
.
ErrTokenNotExist
}
var
t
pty
.
Token
err
=
types
.
Decode
(
token
,
&
t
)
if
err
!=
nil
{
tokenlog
.
Error
(
"tokendb load"
,
"Can't decode token info"
,
symbol
)
return
nil
,
err
}
return
&
tokenDB
{
t
},
nil
}
func
(
t
*
tokenDB
)
mint
(
db
dbm
.
KV
,
addr
string
,
amount
int64
)
([]
*
types
.
KeyValue
,
[]
*
types
.
ReceiptLog
,
error
)
{
if
t
.
token
.
Owner
!=
addr
{
return
nil
,
nil
,
types
.
ErrNotAllow
}
if
t
.
token
.
Total
+
amount
>
types
.
MaxTokenBalance
{
return
nil
,
nil
,
types
.
ErrAmount
}
prevToken
:=
t
.
token
t
.
token
.
Total
+=
amount
kvs
:=
append
(
t
.
getKVSet
(
calcTokenKey
(
t
.
token
.
Symbol
)),
t
.
getKVSet
(
calcTokenAddrNewKeyS
(
t
.
token
.
Symbol
,
t
.
token
.
Owner
))
...
)
logs
:=
[]
*
types
.
ReceiptLog
{{
Ty
:
pty
.
TyLogTokenMint
,
Log
:
types
.
Encode
(
&
pty
.
ReceiptTokenAmount
{
Prev
:
&
prevToken
,
Current
:
&
t
.
token
})}}
return
kvs
,
logs
,
nil
}
func
(
t
*
tokenDB
)
burn
(
db
dbm
.
KV
,
amount
int64
)
([]
*
types
.
KeyValue
,
[]
*
types
.
ReceiptLog
,
error
)
{
if
t
.
token
.
Total
<
amount
{
return
nil
,
nil
,
types
.
ErrNoBalance
}
prevToken
:=
t
.
token
t
.
token
.
Total
-=
amount
kvs
:=
append
(
t
.
getKVSet
(
calcTokenKey
(
t
.
token
.
Symbol
)),
t
.
getKVSet
(
calcTokenAddrNewKeyS
(
t
.
token
.
Symbol
,
t
.
token
.
Owner
))
...
)
logs
:=
[]
*
types
.
ReceiptLog
{{
Ty
:
pty
.
TyLogTokenBurn
,
Log
:
types
.
Encode
(
&
pty
.
ReceiptTokenAmount
{
Prev
:
&
prevToken
,
Current
:
&
t
.
token
})}}
return
kvs
,
logs
,
nil
}
func
getTokenFromDB
(
db
dbm
.
KV
,
symbol
string
,
owner
string
)
(
*
pty
.
Token
,
error
)
{
key
:=
calcTokenAddrKeyS
(
symbol
,
owner
)
value
,
err
:=
db
.
Get
(
key
)
...
...
@@ -468,3 +513,87 @@ func validSymbolWithHeight(cs []byte, height int64) bool {
}
return
validSymbolOriginal
(
cs
)
}
// 铸币不可控, 也是麻烦。 2选1
// 1. 谁可以发起
// 2. 是否需要审核 这个会增加管理的成本
// 现在实现选择 1
func
(
action
*
tokenAction
)
mint
(
mint
*
pty
.
TokenMint
)
(
*
types
.
Receipt
,
error
)
{
if
mint
==
nil
{
return
nil
,
types
.
ErrInvalidParam
}
if
mint
.
GetAmount
()
<
0
||
mint
.
GetAmount
()
>
types
.
MaxTokenBalance
||
mint
.
GetSymbol
()
==
""
{
return
nil
,
types
.
ErrInvalidParam
}
tokendb
,
err
:=
loadTokenDB
(
action
.
db
,
mint
.
GetSymbol
())
if
err
!=
nil
{
return
nil
,
err
}
if
tokendb
.
token
.
Category
&
pty
.
CategoryMintBurnSupport
==
0
{
tokenlog
.
Error
(
"Can't mint category"
,
"category"
,
tokendb
.
token
.
Category
,
"support"
,
pty
.
CategoryMintBurnSupport
)
return
nil
,
types
.
ErrNotSupport
}
kvs
,
logs
,
err
:=
tokendb
.
mint
(
action
.
db
,
action
.
fromaddr
,
mint
.
Amount
)
if
err
!=
nil
{
tokenlog
.
Error
(
"token mint "
,
"symbol"
,
mint
.
GetSymbol
(),
"error"
,
err
,
"from"
,
action
.
fromaddr
,
"owner"
,
tokendb
.
token
.
Owner
)
return
nil
,
err
}
tokenAccount
,
err
:=
account
.
NewAccountDB
(
"token"
,
mint
.
GetSymbol
(),
action
.
db
)
if
err
!=
nil
{
return
nil
,
err
}
tokenlog
.
Debug
(
"mint"
,
"token.Owner"
,
mint
.
Symbol
,
"token.GetTotal()"
,
mint
.
Amount
)
receipt
,
err
:=
tokenAccount
.
Mint
(
action
.
fromaddr
,
mint
.
Amount
)
if
err
!=
nil
{
return
nil
,
err
}
logs
=
append
(
logs
,
receipt
.
Logs
...
)
kvs
=
append
(
kvs
,
receipt
.
KV
...
)
return
&
types
.
Receipt
{
Ty
:
types
.
ExecOk
,
KV
:
kvs
,
Logs
:
logs
},
nil
}
func
(
action
*
tokenAction
)
burn
(
burn
*
pty
.
TokenBurn
)
(
*
types
.
Receipt
,
error
)
{
if
burn
==
nil
{
return
nil
,
types
.
ErrInvalidParam
}
if
burn
.
GetAmount
()
<
0
||
burn
.
GetAmount
()
>
types
.
MaxTokenBalance
||
burn
.
GetSymbol
()
==
""
{
return
nil
,
types
.
ErrInvalidParam
}
tokendb
,
err
:=
loadTokenDB
(
action
.
db
,
burn
.
GetSymbol
())
if
err
!=
nil
{
return
nil
,
err
}
if
tokendb
.
token
.
Category
&
pty
.
CategoryMintBurnSupport
==
0
{
tokenlog
.
Error
(
"Can't burn category"
,
"category"
,
tokendb
.
token
.
Category
,
"support"
,
pty
.
CategoryMintBurnSupport
)
return
nil
,
types
.
ErrNotSupport
}
kvs
,
logs
,
err
:=
tokendb
.
burn
(
action
.
db
,
burn
.
Amount
)
if
err
!=
nil
{
tokenlog
.
Error
(
"token burn "
,
"symbol"
,
burn
.
GetSymbol
(),
"error"
,
err
,
"from"
,
action
.
fromaddr
,
"owner"
,
tokendb
.
token
.
Owner
)
return
nil
,
err
}
tokenAccount
,
err
:=
account
.
NewAccountDB
(
"token"
,
burn
.
GetSymbol
(),
action
.
db
)
if
err
!=
nil
{
return
nil
,
err
}
tokenlog
.
Debug
(
"burn"
,
"token.Owner"
,
burn
.
Symbol
,
"token.GetTotal()"
,
burn
.
Amount
)
receipt
,
err
:=
tokenAccount
.
Burn
(
action
.
fromaddr
,
burn
.
Amount
)
if
err
!=
nil
{
return
nil
,
err
}
logs
=
append
(
logs
,
receipt
.
Logs
...
)
kvs
=
append
(
kvs
,
receipt
.
KV
...
)
return
&
types
.
Receipt
{
Ty
:
types
.
ExecOk
,
KV
:
kvs
,
Logs
:
logs
},
nil
}
plugin/dapp/token/executor/transwithdraw.go
View file @
65ba0be8
...
...
@@ -172,7 +172,10 @@ func updateAddrReciver(cachedb dbm.KVDB, token string, addr string, amount int64
}
else
{
recv
-=
amount
}
setAddrReciver
(
cachedb
,
token
,
addr
,
recv
)
err
=
setAddrReciver
(
cachedb
,
token
,
addr
,
recv
)
if
err
!=
nil
{
return
nil
,
err
}
//keyvalue
return
getAddrReciverKV
(
token
,
addr
,
recv
),
nil
}
plugin/dapp/token/proto/token.proto
View file @
65ba0be8
...
...
@@ -15,6 +15,8 @@ message TokenAction {
AssetsWithdraw
withdraw
=
5
;
AssetsGenesis
genesis
=
6
;
AssetsTransferToExec
transferToExec
=
8
;
TokenMint
tokenMint
=
9
;
TokenBurn
tokenBurn
=
10
;
}
int32
Ty
=
7
;
}
...
...
@@ -40,6 +42,16 @@ message TokenRevokeCreate {
string
owner
=
2
;
}
message
TokenMint
{
string
symbol
=
1
;
int64
amount
=
2
;
}
message
TokenBurn
{
string
symbol
=
1
;
int64
amount
=
2
;
}
// state db
message
Token
{
string
name
=
1
;
...
...
@@ -60,6 +72,11 @@ message ReceiptToken {
int32
status
=
3
;
}
message
ReceiptTokenAmount
{
Token
prev
=
1
;
Token
current
=
2
;
}
// local
message
LocalToken
{
string
name
=
1
;
...
...
@@ -82,6 +99,13 @@ message LocalToken {
int32
category
=
17
;
}
message
LocalLogs
{
string
symbol
=
1
;
string
txIndex
=
2
;
int32
actionType
=
3
;
string
txHash
=
4
;
}
// query
message
ReqTokens
{
bool
queryAll
=
1
;
...
...
@@ -142,6 +166,10 @@ message ReqTokenTx {
string
addr
=
7
;
}
message
ReplyTokenLogs
{
repeated
LocalLogs
logs
=
1
;
}
service
token
{
// token 对外提供服务的接口
//区块链接口
...
...
plugin/dapp/token/rpc/rpc.go
View file @
65ba0be8
...
...
@@ -121,3 +121,29 @@ func (c *Jrpc) CreateRawTokenRevokeTx(param *tokenty.TokenRevokeCreate, result *
*
result
=
hex
.
EncodeToString
(
data
)
return
nil
}
// CreateRawTokenMintTx 创建未签名的mint Token交易
func
(
c
*
Jrpc
)
CreateRawTokenMintTx
(
param
*
tokenty
.
TokenMint
,
result
*
interface
{})
error
{
if
param
==
nil
||
param
.
Symbol
==
""
||
param
.
Amount
<=
0
{
return
types
.
ErrInvalidParam
}
data
,
err
:=
types
.
CallCreateTx
(
types
.
ExecName
(
tokenty
.
TokenX
),
"TokenMint"
,
param
)
if
err
!=
nil
{
return
err
}
*
result
=
hex
.
EncodeToString
(
data
)
return
nil
}
// CreateRawTokenBurnTx 创建未签名的 burn Token交易
func
(
c
*
Jrpc
)
CreateRawTokenBurnTx
(
param
*
tokenty
.
TokenBurn
,
result
*
interface
{})
error
{
if
param
==
nil
||
param
.
Symbol
==
""
||
param
.
Amount
<=
0
{
return
types
.
ErrInvalidParam
}
data
,
err
:=
types
.
CallCreateTx
(
types
.
ExecName
(
tokenty
.
TokenX
),
"TokenBurn"
,
param
)
if
err
!=
nil
{
return
err
}
*
result
=
hex
.
EncodeToString
(
data
)
return
nil
}
plugin/dapp/token/types/const.go
View file @
65ba0be8
...
...
@@ -19,6 +19,10 @@ const (
TokenActionRevokeCreate
=
9
// TokenActionTransferToExec for token transfer to exec
TokenActionTransferToExec
=
11
// TokenActionMint for token mint
TokenActionMint
=
12
// TokenActionBurn for token burn
TokenActionBurn
=
13
)
// token status
...
...
@@ -72,6 +76,10 @@ const (
TyLogTokenGenesisTransfer
=
321
// TyLogTokenGenesisDeposit log for token genesis deposit
TyLogTokenGenesisDeposit
=
322
// TyLogTokenMint log for token mint
TyLogTokenMint
=
323
// TyLogTokenBurn log for token burn
TyLogTokenBurn
=
324
)
const
(
...
...
@@ -82,3 +90,8 @@ const (
// TokenIntroLenLimit token introduction length limit
TokenIntroLenLimit
=
1024
)
const
(
// CategoryMintBurnSupport support mint & burn
CategoryMintBurnSupport
=
1
<<
iota
)
plugin/dapp/token/types/token.pb.go
View file @
65ba0be8
This diff is collapsed.
Click to expand it.
plugin/dapp/token/types/types.go
View file @
65ba0be8
...
...
@@ -57,6 +57,8 @@ func (t *TokenType) GetTypeMap() map[string]int32 {
"TokenFinishCreate"
:
TokenActionFinishCreate
,
"TokenRevokeCreate"
:
TokenActionRevokeCreate
,
"TransferToExec"
:
TokenActionTransferToExec
,
"TokenMint"
:
TokenActionMint
,
"TokenBurn"
:
TokenActionBurn
,
}
}
...
...
@@ -75,6 +77,8 @@ func (t *TokenType) GetLogMap() map[int64]*types.LogInfo {
TyLogPreCreateToken
:
{
Ty
:
reflect
.
TypeOf
(
ReceiptToken
{}),
Name
:
"LogPreCreateToken"
},
TyLogFinishCreateToken
:
{
Ty
:
reflect
.
TypeOf
(
ReceiptToken
{}),
Name
:
"LogFinishCreateToken"
},
TyLogRevokeCreateToken
:
{
Ty
:
reflect
.
TypeOf
(
ReceiptToken
{}),
Name
:
"LogRevokeCreateToken"
},
TyLogTokenMint
:
{
Ty
:
reflect
.
TypeOf
(
ReceiptTokenAmount
{}),
Name
:
"LogMintToken"
},
TyLogTokenBurn
:
{
Ty
:
reflect
.
TypeOf
(
ReceiptTokenAmount
{}),
Name
:
"LogBurnToken"
},
}
}
...
...
vendor/github.com/33cn/chain33/account/account_test.go
View file @
65ba0be8
...
...
@@ -601,3 +601,4 @@ func TestDB_Burn(t *testing.T) {
t
.
Logf
(
"Token mint addr balance [%d]"
,
tokenCoin
.
LoadAccount
(
addr1
)
.
Balance
)
require
.
Equal
(
t
,
int64
(
1000
*
1e8
-
10
*
1e8
),
tokenCoin
.
LoadAccount
(
addr1
)
.
Balance
)
}
vendor/github.com/33cn/chain33/types/proto/account.proto
View file @
65ba0be8
...
...
@@ -80,4 +80,4 @@ message ReqAllExecBalance {
string
stateHash
=
3
;
string
asset_exec
=
4
;
string
asset_symbol
=
5
;
}
\ No newline at end of file
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment