Commit bdc1ab9a authored by mdj33's avatar mdj33 Committed by vipwzw

cross asset transfer

parent bb9f022e
......@@ -32,6 +32,7 @@ func ParcCmd() *cobra.Command {
CreateRawTransferCmd(),
CreateRawWithdrawCmd(),
CreateRawTransferToExecCmd(),
CreateRawCrossAssetTransferCmd(),
superNodeCmd(),
nodeGroupCmd(),
paraConfigCmd(),
......@@ -236,6 +237,75 @@ func createWithdraw(cmd *cobra.Command, args []string) {
commands.CreateAssetWithdraw(cmd, args, pt.ParaX)
}
// CreateRawCrossAssetTransferCmd create raw cross asset transfer tx
func CreateRawCrossAssetTransferCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "cross_transfer",
Short: "Create a cross asset transfer transaction",
Run: createCrossAssetTransfer,
}
addCreateCrossAssetTransferFlags(cmd)
return cmd
}
func addCreateCrossAssetTransferFlags(cmd *cobra.Command) {
cmd.Flags().Uint32P("type", "d", 0, "transfer type: 0:to paraChain, 1:to mainChain")
cmd.MarkFlagRequired("type")
cmd.Flags().StringP("to", "t", "", "transfer to account")
cmd.MarkFlagRequired("to")
cmd.Flags().Float64P("amount", "a", 0, "transaction amount")
cmd.MarkFlagRequired("amount")
cmd.Flags().StringP("note", "n", "", "transaction note info")
cmd.Flags().StringP("symbol", "s", "", "default for bty, parachain symbol like user.p.xx.bty")
}
func createCrossAssetTransfer(cmd *cobra.Command, args []string) {
ty, _ := cmd.Flags().GetUint32("type")
toAddr, _ := cmd.Flags().GetString("to")
note, _ := cmd.Flags().GetString("note")
symbol, _ := cmd.Flags().GetString("symbol")
amount, _ := cmd.Flags().GetFloat64("amount")
if amount < 0 {
fmt.Fprintln(os.Stderr, "amount < 0")
return
}
amountInt64 := int64(math.Trunc((amount+0.0000001)*1e4)) * 1e4
paraName, _ := cmd.Flags().GetString("paraName")
if !strings.HasPrefix(paraName, "user.p") {
fmt.Fprintln(os.Stderr, "paraName is not right, paraName format like `user.p.guodun.`")
return
}
execName := paraName + pt.ParaX
if ty > 0 && symbol == "" {
fmt.Fprintln(os.Stderr, "transfer to main chain, symbol should not be null")
return
}
var config pt.CrossAssetTransfer
config.Type = ty
config.AssetSymbol = symbol
config.ToAddr = toAddr
config.Note = note
config.Amount = amountInt64
params := &rpctypes.CreateTxIn{
Execer: execName,
ActionName: "CrossAssetTransfer",
Payload: types.MustPBToJSON(&config),
}
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.CreateTransaction", params, nil)
ctx.RunWithoutMarshal()
}
func superNodeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "super_node",
......@@ -1015,7 +1085,7 @@ func paraAssetTransfer(cmd *cobra.Command, args []string) {
}
params.Payload = types.MustPBToJSON(&req)
var res pt.ParacrossAssetRsp
var res pt.ParacrossAsset
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.Query", params, &res)
ctx.Run()
}
......
......@@ -10,6 +10,7 @@ import (
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
......@@ -101,7 +102,7 @@ func checkCommitInfo(cfg *types.Chain33Config, commit *pt.ParacrossCommitAction)
return types.ErrInvalidParam
}
clog.Debug("paracross.Commit check input", "height", commit.Status.Height, "mainHeight", commit.Status.MainBlockHeight,
"mainHash", hex.EncodeToString(commit.Status.MainBlockHash), "blockHash", hex.EncodeToString(commit.Status.BlockHash))
"mainHash", common.ToHex(commit.Status.MainBlockHash), "blockHash", common.ToHex(commit.Status.BlockHash))
if commit.Status.Height == 0 {
if len(commit.Status.Title) == 0 || len(commit.Status.BlockHash) == 0 {
......@@ -355,8 +356,8 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
if titleStatus.Height+1 == commit.Status.Height && commit.Status.Height > 0 && !pt.IsParaForkHeight(cfg, commit.Status.MainBlockHeight, pt.ForkLoopCheckCommitTxDone) {
if !bytes.Equal(titleStatus.BlockHash, commit.Status.PreBlockHash) {
clog.Error("paracross.Commit", "check PreBlockHash", hex.EncodeToString(titleStatus.BlockHash),
"commit tx", hex.EncodeToString(commit.Status.PreBlockHash), "commitheit", commit.Status.Height,
clog.Error("paracross.Commit", "check PreBlockHash", common.ToHex(titleStatus.BlockHash),
"commit tx", common.ToHex(commit.Status.PreBlockHash), "commitheit", commit.Status.Height,
"from", a.fromaddr)
return nil, pt.ErrParaBlockHashNoMatch
}
......@@ -388,8 +389,8 @@ func (a *action) Commit(commit *pt.ParacrossCommitAction) (*types.Receipt, error
//对于主链,校验的是主链高度对应的blockhash是否和commit的一致
//对于平行链, 校验的是commit信息的平行链height block对应的mainHash是否和本地相同高度对应的mainHash一致, 在主链hash一致的时候看平行链共识blockhash是否一致
if !bytes.Equal(dbMainHash, commit.Status.MainBlockHash) && commit.Status.Height > 0 {
clog.Error("paracross.Commit blockHash not match", "isMain", !cfg.IsPara(), "db", hex.EncodeToString(dbMainHash),
"commit", hex.EncodeToString(commit.Status.MainBlockHash), "commitHeight", commit.Status.Height,
clog.Error("paracross.Commit blockHash not match", "isMain", !cfg.IsPara(), "db", common.ToHex(dbMainHash),
"commit", common.ToHex(commit.Status.MainBlockHash), "commitHeight", commit.Status.Height,
"commitMainHeight", commit.Status.MainBlockHeight, "from", a.fromaddr)
return nil, types.ErrBlockHashNoMatch
}
......@@ -488,7 +489,7 @@ func (a *action) commitTxDone(nodeStatus *pt.ParacrossNodeStatus, stat *pt.Parac
clog.Debug("paracross.Commit commit", "stat.title", stat.Title, "stat.height", stat.Height, "notes", len(nodes))
for i, v := range stat.Details.Addrs {
clog.Debug("paracross.Commit commit detail", "addr", v, "hash", hex.EncodeToString(stat.Details.BlockHash[i]))
clog.Debug("paracross.Commit commit detail", "addr", v, "hash", common.ToHex(stat.Details.BlockHash[i]))
}
commitCount := len(stat.Details.Addrs)
......@@ -496,7 +497,7 @@ func (a *action) commitTxDone(nodeStatus *pt.ParacrossNodeStatus, stat *pt.Parac
if !isCommitDone(nodes, most) {
return receipt, nil
}
clog.Debug("paracross.Commit commit ----pass", "most", most, "mostHash", hex.EncodeToString([]byte(mostHash)))
clog.Debug("paracross.Commit commit ----pass", "most", most, "mostHash", common.ToHex([]byte(mostHash)))
stat.Status = pt.ParacrossStatusCommitDone
saveTitleHeight(a.db, calcTitleHeightKey(stat.Title, stat.Height), stat)
......@@ -532,20 +533,20 @@ func (a *action) commitTxDoneStep2(nodeStatus *pt.ParacrossNodeStatus, stat *pt.
}
saveTitle(a.db, calcTitleKey(titleStatus.Title), titleStatus)
clog.Debug("paracross.Commit commit done", "height", nodeStatus.Height, "statusBlockHash", hex.EncodeToString(nodeStatus.BlockHash))
clog.Debug("paracross.Commit commit done", "height", nodeStatus.Height, "statusBlockHash", common.ToHex(nodeStatus.BlockHash))
//parallel chain not need to process cross commit tx here
if cfg.IsPara() {
//平行链自共识校验
selfBlockHash, err := getBlockHash(a.api, nodeStatus.Height)
if err != nil {
clog.Error("paracross.CommitDone getBlockHash", "err", err, "commit tx height", nodeStatus.Height, "tx", hex.EncodeToString(a.txhash))
clog.Error("paracross.CommitDone getBlockHash", "err", err, "commit tx height", nodeStatus.Height, "tx", common.ToHex(a.txhash))
return nil, err
}
//说明本节点blockhash和共识hash不一致,需要停止本节点执行
if !bytes.Equal(selfBlockHash.Hash, nodeStatus.BlockHash) {
clog.Error("paracross.CommitDone mosthash not match", "height", nodeStatus.Height,
"blockHash", hex.EncodeToString(selfBlockHash.Hash), "mosthash", hex.EncodeToString(nodeStatus.BlockHash))
"blockHash", common.ToHex(selfBlockHash.Hash), "mosthash", common.ToHex(nodeStatus.BlockHash))
return nil, types.ErrConsensusHashErr
}
......@@ -554,7 +555,7 @@ func (a *action) commitTxDoneStep2(nodeStatus *pt.ParacrossNodeStatus, stat *pt.
//错误会导致和主链处理的共识结果不一致
if err != nil {
clog.Error("paracross mining reward err", "height", nodeStatus.Height,
"blockhash", hex.EncodeToString(nodeStatus.BlockHash), "err", err)
"blockhash", common.ToHex(nodeStatus.BlockHash), "err", err)
return nil, err
}
receipt = mergeReceipt(receipt, rewardReceipt)
......@@ -666,7 +667,7 @@ func (a *action) commitTxDoneByStat(stat *pt.ParacrossHeightStatus, titleStatus
receipt := &types.Receipt{}
clog.Debug("paracross.commitTxDoneByStat", "stat.title", stat.Title, "stat.height", stat.Height, "notes", len(nodes))
for i, v := range stat.Details.Addrs {
clog.Debug("paracross.commitTxDoneByStat detail", "addr", v, "hash", hex.EncodeToString(stat.Details.BlockHash[i]))
clog.Debug("paracross.commitTxDoneByStat detail", "addr", v, "hash", common.ToHex(stat.Details.BlockHash[i]))
}
updateCommitAddrs(stat, nodes)
......@@ -675,7 +676,7 @@ func (a *action) commitTxDoneByStat(stat *pt.ParacrossHeightStatus, titleStatus
if !isCommitDone(nodes, most) {
return nil, nil
}
clog.Debug("paracross.commitTxDoneByStat ----pass", "most", most, "mostHash", hex.EncodeToString([]byte(mostHash)))
clog.Debug("paracross.commitTxDoneByStat ----pass", "most", most, "mostHash", common.ToHex([]byte(mostHash)))
stat.Status = pt.ParacrossStatusCommitDone
saveTitleHeight(a.db, calcTitleHeightKey(stat.Title, stat.Height), stat)
r := makeCommitStatReceipt(stat)
......@@ -752,18 +753,21 @@ func execCrossTx(a *action, tx *types.TransactionDetail, crossTxHash []byte) (*t
var payload pt.ParacrossAction
err := types.Decode(tx.Tx.Payload, &payload)
if err != nil {
clog.Crit("paracross.Commit Decode Tx failed", "error", err, "txHash", hex.EncodeToString(crossTxHash))
clog.Crit("paracross.Commit Decode Tx failed", "error", err, "txHash", common.ToHex(crossTxHash))
return nil, err
}
}
//主链共识后,执行主链资产withdraw, 在支持CrossAssetTransfer之前使用此action
if payload.Ty == pt.ParacrossActionAssetWithdraw {
receiptWithdraw, err := a.assetWithdraw(payload.GetAssetWithdraw(), tx.Tx)
if err != nil {
clog.Crit("paracross.Commit withdraw Tx failed", "error", err, "txHash", hex.EncodeToString(crossTxHash))
clog.Crit("paracross.Commit withdraw Tx failed", "error", err, "txHash", common.ToHex(crossTxHash))
return nil, errors.Cause(err)
}
clog.Debug("paracross.Commit WithdrawCoins", "txHash", hex.EncodeToString(crossTxHash))
clog.Debug("paracross.Commit WithdrawCoins", "txHash", common.ToHex(crossTxHash))
return receiptWithdraw, nil
}
return nil, nil
......@@ -777,18 +781,73 @@ func rollbackCrossTx(a *action, tx *types.TransactionDetail, crossTxHash []byte)
var payload pt.ParacrossAction
err := types.Decode(tx.Tx.Payload, &payload)
if err != nil {
clog.Crit("paracross.Commit.rollbackCrossTx Decode Tx failed", "error", err, "txHash", hex.EncodeToString(crossTxHash))
clog.Crit("paracross.Commit.rollbackCrossTx Decode Tx failed", "error", err, "txHash", common.ToHex(crossTxHash))
return nil, err
}
if payload.Ty == pt.ParacrossActionCrossAssetTransfer {
act, err := getCrossAction(payload.GetCrossAssetTransfer(), string(a.tx.Execer))
if err != nil {
clog.Crit("paracross.Commit getCrossAction Tx failed", "error", err, "txHash", common.ToHex(crossTxHash))
return nil, err
}
if act == pt.ParacrossMainWithdraw || act == pt.ParacrossParaTransfer {
receipt, err := a.crossAssetTransfer(payload.GetCrossAssetTransfer(), act, tx.Tx)
if err != nil {
clog.Crit("paracross.Commit crossAssetTransfer Tx failed", "error", err, "act", act, "txHash", common.ToHex(crossTxHash))
return nil, err
}
clog.Debug("paracross.Commit crossAssetTransfer done", "act", act, "txHash", common.ToHex(crossTxHash))
return receipt, nil
}
if payload.Ty == pt.ParacrossActionCrossAssetTransfer {
act, err := getCrossAction(payload.GetCrossAssetTransfer(), string(a.tx.Execer))
if err != nil {
clog.Crit("paracross.Commit.rollbackCrossTx getCrossAction failed", "error", err, "txHash", common.ToHex(crossTxHash))
return nil, err
}
//主链共识后,平行链执行出错的主链资产transfer回滚
if act == pt.ParacrossMainTransfer {
receipt, err := a.assetTransferRollback(payload.GetCrossAssetTransfer(), tx.Tx)
if err != nil {
clog.Crit("paracross.Commit crossAssetTransfer rbk failed", "error", err, "txHash", common.ToHex(crossTxHash))
return nil, errors.Cause(err)
}
clog.Debug("paracross.Commit crossAssetTransfer rollbackCrossTx", "txHash", common.ToHex(crossTxHash), "mainHeight", a.height)
return receipt, nil
}
//主链共识后,平行链执行出错的平行链资产withdraw回滚
if act == pt.ParacrossParaWithdraw {
receipt, err := a.paraAssetWithdrawRollback(payload.GetCrossAssetTransfer(), tx.Tx)
if err != nil {
clog.Crit("paracross.Commit rbk paraAssetWithdraw Tx failed", "error", err, "txHash", common.ToHex(crossTxHash))
return nil, errors.Cause(err)
}
clog.Debug("paracross.Commit paraAssetWithdraw rollbackCrossTx", "txHash", common.ToHex(crossTxHash), "mainHeight", a.height)
return receipt, nil
}
}
//主链共识后,平行链执行出错的主链资产transfer回滚
if payload.Ty == pt.ParacrossActionAssetTransfer {
receipt, err := a.assetTransferRollback(payload.GetAssetTransfer(), tx.Tx)
assettf := payload.GetAssetTransfer()
cross := &pt.CrossAssetTransfer{
AssetSymbol: assettf.Cointoken,
Amount: assettf.Amount,
Note: string(assettf.Note),
ToAddr: assettf.To,
}
receipt, err := a.assetTransferRollback(cross, tx.Tx)
if err != nil {
clog.Crit("paracross.Commit rbk Tx failed", "error", err, "txHash", hex.EncodeToString(crossTxHash))
clog.Crit("paracross.Commit rbk asset transfer Tx failed", "error", err, "txHash", common.ToHex(crossTxHash))
return nil, errors.Cause(err)
}
clog.Debug("paracross.Commit rollbackCrossTx", "txHash", hex.EncodeToString(crossTxHash), "mainHeight", a.height)
clog.Debug("paracross.Commit assetTransfer rollbackCrossTx", "txHash", common.ToHex(crossTxHash), "mainHeight", a.height)
return receipt, nil
}
return nil, nil
......@@ -824,7 +883,7 @@ func getCrossTxHashsByRst(api client.QueueProtocolAPI, status *pt.ParacrossNodeS
}
paraCrossHashs := FilterParaCrossTxHashes(paraAllTxs)
crossRst := util.CalcBitMapByBitMap(paraCrossHashs, baseHashs, rst)
clog.Debug("getCrossTxHashsByRst.crossRst", "height", status.Height, "txResult", hex.EncodeToString(crossRst), "len", len(paraCrossHashs))
clog.Debug("getCrossTxHashsByRst.crossRst", "height", status.Height, "txResult", common.ToHex(crossRst), "len", len(paraCrossHashs))
return paraCrossHashs, crossRst, nil
......@@ -841,7 +900,7 @@ func getCrossTxHashs(api client.QueueProtocolAPI, status *pt.ParacrossNodeStatus
if len(status.CrossTxHashs) == 0 {
clog.Error("getCrossTxHashs len=0", "paraHeight", status.Height,
"mainHeight", status.MainBlockHeight, "mainHash", hex.EncodeToString(status.MainBlockHash))
"mainHeight", status.MainBlockHeight, "mainHash", common.ToHex(status.MainBlockHash))
return nil, nil, types.ErrCheckTxHash
}
......@@ -860,14 +919,14 @@ func getCrossTxHashs(api client.QueueProtocolAPI, status *pt.ParacrossNodeStatus
crossCheckHash := CalcTxHashsHash(paraCrossHashs)
if !bytes.Equal(status.CrossTxHashs[0], crossCheckHash) {
clog.Error("getCrossTxHashs para hash not equal", "paraHeight", status.Height,
"mainHeight", status.MainBlockHeight, "mainHash", hex.EncodeToString(status.MainBlockHash),
"main.crossHash", hex.EncodeToString(crossCheckHash), "commit.crossHash", hex.EncodeToString(status.CrossTxHashs[0]),
"main.baseHash", hex.EncodeToString(baseCheckTxHash), "commit.baseHash", hex.EncodeToString(status.TxHashs[0]))
"mainHeight", status.MainBlockHeight, "mainHash", common.ToHex(status.MainBlockHash),
"main.crossHash", common.ToHex(crossCheckHash), "commit.crossHash", common.ToHex(status.CrossTxHashs[0]),
"main.baseHash", common.ToHex(baseCheckTxHash), "commit.baseHash", common.ToHex(status.TxHashs[0]))
for _, hash := range baseHashs {
clog.Error("getCrossTxHashs base tx hash", "txhash", hex.EncodeToString(hash))
clog.Error("getCrossTxHashs base tx hash", "txhash", common.ToHex(hash))
}
for _, hash := range paraCrossHashs {
clog.Error("getCrossTxHashs paracross tx hash", "txhash", hex.EncodeToString(hash))
clog.Error("getCrossTxHashs paracross tx hash", "txhash", common.ToHex(hash))
}
return nil, nil, types.ErrCheckTxHash
}
......@@ -886,11 +945,11 @@ func getCrossTxHashs(api client.QueueProtocolAPI, status *pt.ParacrossNodeStatus
func crossTxProc(a *action, txHash []byte, fn func(*action, *types.TransactionDetail, []byte) (*types.Receipt, error)) (*types.Receipt, error) {
tx, err := GetTx(a.api, txHash)
if err != nil {
clog.Crit("paracross.Commit Load Tx failed", "error", err, "txHash", hex.EncodeToString(txHash))
clog.Crit("paracross.Commit Load Tx failed", "error", err, "txHash", common.ToHex(txHash))
return nil, err
}
if tx == nil {
clog.Error("paracross.Commit Load Tx nil", "error", err, "txHash", hex.EncodeToString(txHash))
clog.Error("paracross.Commit Load Tx nil", "error", err, "txHash", common.ToHex(txHash))
return nil, types.ErrHashNotExist
}
receiptCross, err := fn(a, tx, txHash)
......@@ -911,7 +970,7 @@ func (a *action) execCrossTxs(status *pt.ParacrossNodeStatus) (*types.Receipt, e
}
for i := 0; i < len(crossTxHashs); i++ {
clog.Debug("paracross.Commit commitDone", "do cross number", i, "hash", hex.EncodeToString(crossTxHashs[i]),
clog.Debug("paracross.Commit commitDone", "do cross number", i, "hash", common.ToHex(crossTxHashs[i]),
"res", util.BitMapBit(crossTxResult, uint32(i)))
if util.BitMapBit(crossTxResult, uint32(i)) {
receiptCross, err := crossTxProc(a, crossTxHashs[i], execCrossTx)
......@@ -927,7 +986,7 @@ func (a *action) execCrossTxs(status *pt.ParacrossNodeStatus) (*types.Receipt, e
receipt.Logs = append(receipt.Logs, receiptCross.Logs...)
} else {
clog.Error("paracross.Commit commitDone", "do cross number", i, "hash",
hex.EncodeToString(crossTxHashs[i]), "para res", util.BitMapBit(crossTxResult, uint32(i)))
common.ToHex(crossTxHashs[i]), "para res", util.BitMapBit(crossTxResult, uint32(i)))
cfg := a.api.GetConfig()
if cfg.IsDappFork(a.height, pt.ParaX, pt.ForkParaAssetTransferRbk) {
receiptCross, err := crossTxProc(a, crossTxHashs[i], rollbackCrossTx)
......@@ -973,7 +1032,7 @@ func (a *action) AssetWithdraw(withdraw *types.AssetsWithdraw) (*types.Receipt,
return nil, nil
}
clog.Debug("paracross.AssetWithdraw isPara", "execer", string(a.tx.Execer),
"txHash", hex.EncodeToString(a.tx.Hash()), "token name", withdraw.Cointoken)
"txHash", common.ToHex(a.tx.Hash()), "token name", withdraw.Cointoken)
receipt, err := a.assetWithdraw(withdraw, a.tx)
if err != nil {
clog.Error("AssetWithdraw failed", "err", err)
......@@ -982,6 +1041,27 @@ func (a *action) AssetWithdraw(withdraw *types.AssetsWithdraw) (*types.Receipt,
return receipt, nil
}
func (a *action) CrossAssetTransfer(transfer *pt.CrossAssetTransfer) (*types.Receipt, error) {
clog.Debug("Paracross.CrossAssetTransfer", "exec", transfer.AssetExec, "symbol", transfer.AssetSymbol)
cfg := a.api.GetConfig()
isPara := cfg.IsPara()
act, err := getCrossAction(transfer, string(a.tx.Execer))
if act == pt.ParacrossNoneTransfer {
return nil, err
}
// 需要平行链先执行, 达成共识时,继续执行
if !isPara && (act == pt.ParacrossMainWithdraw || act == pt.ParacrossParaTransfer) {
return nil, nil
}
receipt, err := a.crossAssetTransfer(transfer, act, a.tx)
if err != nil {
clog.Error("CrossAssetTransfer failed", "err", err)
return nil, err
}
return receipt, nil
}
//当前miner tx不需要校验上一个区块的衔接性,因为tx就是本节点发出,高度,preHash等都在本区块里面的blockchain做了校验
func (a *action) Miner(miner *pt.ParacrossMinerAction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
......@@ -1057,7 +1137,7 @@ func (a *Paracross) CrossLimits(tx *types.Transaction, index int) bool {
txs, err := a.GetTxGroup(index)
if err != nil {
clog.Error("crossLimits", "get tx group failed", err, "hash", hex.EncodeToString(tx.Hash()))
clog.Error("crossLimits", "get tx group failed", err, "hash", common.ToHex(tx.Hash()))
return false
}
......
......@@ -7,94 +7,300 @@ package executor
import (
"encoding/hex"
"strings"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/db"
coins "github.com/33cn/chain33/system/dapp/coins/types"
"github.com/33cn/chain33/types"
pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
token "github.com/33cn/plugin/plugin/dapp/token/types"
"github.com/pkg/errors"
)
func (a *action) assetTransfer(transfer *types.AssetsTransfer) (*types.Receipt, error) {
const SYMBOL_BTY = "bty"
//平行链向主链transfer,先在平行链处理,共识后再在主链铸造
//主链的token转移到user.p.bb.平行链,在平行链上表示为mavl-paracross-token.symbol:
//主链的平行链转移进来的token在主链表示为mavl-paracross-user.p.aa.token.symbol 转移到user.p.bb.平行链,在平行链bb上表示mavl-paracross-paracross.user.p.aa.token.symbol
//在用户看来,平行链的资产是user.p.test.ccny, 主链资产是coins.bty, 平行链往主链转还是主链往平行链转都是这个名字
//如果主链上user.p.test.coins.ccny往user.p.test.平行链转,就是withdraw流程,如果往另一个平行链user.p.xx.转,则是转移流程
//主链转移场景: type=0,tx.exec:user.p.test.
//1. 主链本币转移: exec:coins/token symbol:{coins/token}.bty/cny or bty/cny,
// 平行链资产: paracross-coins.bty
//2. 主链外币转移: exec:paracross, symbol: user.p.para.coins.ccny,
// 平行链资产: paracross-paracross.user.p.para.coins.ccny
//3. 平行链本币提回:  exec:coins, symbol: user.p.test.coins.ccny
// 平行链资产: paracross账户coins.ccny资产释放
//平行链转移场景:type=1,tx.exec:user.p.test.
//1. 平行链本币转移: exec:coins/token, symbol:user.p.test.{coins/token}.ccny
// 主链产生资产: paracross-user.p.test.{coins}.ccny
//2. 主链外币提取: exec:paracross, symbol: user.p.para.coins.ccny
// 主链恢复外币资产: user.p.test.paracross地址释放user.p.para.coins.ccny
//3. 主链本币提取: exec:coins/token, symbol: coins.bty
// 主链恢复本币资产: user.p.test.paracross地址释放coin.bty
func getCrossAction(transfer *pt.CrossAssetTransfer, txExecer string) (int64, error) {
paraTitle, ok := types.GetParaExecTitleName(txExecer)
if !ok {
return pt.ParacrossNoneTransfer, errors.Wrapf(types.ErrInvalidParam, "getCrossAction wrong execer:%s", txExecer)
}
//主链向平行链转移, 转移主链资产(包括主链本币和平行链转移进来的外币)或平行链资产withdraw
if transfer.Type == 0 {
// same prefix for paraChain and Symbol
if strings.Contains(transfer.AssetSymbol, paraTitle) {
return pt.ParacrossParaWithdraw, nil
}
// different paraChain symbol or mainChain symbol -> main asset transfer
return pt.ParacrossMainTransfer, nil
}
//从平行链向主链转移,平行链资产转移或者主链资产withdraw
//symbol和paraChain prefix一致,或者symbol没有"." -> para asset transfer
if strings.Contains(transfer.AssetSymbol, paraTitle) {
return pt.ParacrossParaTransfer, nil
}
// different paraChain symbol or mainChain symbol or null symbol -> main asset withdraw
return pt.ParacrossMainWithdraw, nil
}
//自动补充一些参数,比如paracross执行器或symbol
func formatTransfer(transfer *pt.CrossAssetTransfer, act int64) *pt.CrossAssetTransfer {
newTransfer := *transfer
if act == pt.ParacrossMainTransfer || act == pt.ParacrossMainWithdraw {
//转移平行链资产到另一个平行链
if strings.HasPrefix(transfer.AssetSymbol, types.ParaKeyX) {
newTransfer.AssetExec = pt.ParaX
return &newTransfer
}
//转移资产symbol为bty 或 token.bty场景
if len(transfer.AssetSymbol) > 0 {
if strings.Contains(transfer.AssetSymbol, ".") {
elements := strings.Split(transfer.AssetSymbol, ".")
newTransfer.AssetExec = elements[len(elements)-2]
newTransfer.AssetSymbol = elements[len(elements)-1]
return &newTransfer
}
newTransfer.AssetExec = token.TokenX
return &newTransfer
}
//assetSymbol 为null
newTransfer.AssetExec = coins.CoinsX
newTransfer.AssetSymbol = SYMBOL_BTY
return &newTransfer
}
//把user.p.{para}.ccny prefix去掉,保留ccny
if act == pt.ParacrossParaTransfer || act == pt.ParacrossParaWithdraw {
e := strings.Split(transfer.AssetSymbol, ".")
newTransfer.AssetSymbol = e[len(e)-1]
newTransfer.AssetExec = e[len(e)-2]
//user.p.xx.ccny,没有写coins 执行器场景
if len(e) == 4 {
newTransfer.AssetExec = coins.CoinsX
}
return &newTransfer
}
return transfer
}
func (a *action) crossAssetTransfer(transfer *pt.CrossAssetTransfer, act int64, actTx *types.Transaction) (*types.Receipt, error) {
newTransfer := formatTransfer(transfer, act)
clog.Info("paracross.crossAssetTransfer", "action", act, "newExec", newTransfer.AssetExec, "newSymbol", newTransfer.AssetSymbol,
"ori.symbol", transfer.AssetSymbol, "type", transfer.Type, "txHash", common.ToHex(a.tx.Hash()))
switch act {
case pt.ParacrossMainTransfer:
return a.mainAssetTransfer(newTransfer)
case pt.ParacrossMainWithdraw:
return a.mainAssetWithdraw(newTransfer, actTx)
case pt.ParacrossParaTransfer:
return a.paraAssetTransfer(newTransfer)
case pt.ParacrossParaWithdraw:
return a.paraAssetWithdraw(newTransfer, actTx)
default:
return nil, types.ErrNotSupport
}
}
func (a *action) mainAssetTransfer(transfer *pt.CrossAssetTransfer) (*types.Receipt, error) {
cfg := a.api.GetConfig()
isPara := cfg.IsPara()
//主链处理分支
if !isPara {
accDB, err := createAccount(cfg, a.db, transfer.Cointoken)
if err != nil {
return nil, errors.Wrap(err, "assetTransferToken call account.NewAccountDB failed")
}
execAddr := address.ExecAddress(pt.ParaX)
fromAcc := accDB.LoadExecAccount(a.fromaddr, execAddr)
if fromAcc.Balance < transfer.Amount {
return nil, errors.Wrap(types.ErrNoBalance, "assetTransfer")
}
toAddr := address.ExecAddress(string(a.tx.Execer))
clog.Debug("paracross.AssetTransfer not isPara", "execer", string(a.tx.Execer),
"txHash", hex.EncodeToString(a.tx.Hash()))
return accDB.ExecTransfer(a.fromaddr, toAddr, execAddr, transfer.Amount)
return a.execTransfer(transfer)
}
return a.execCreateAsset(transfer)
}
func (a *action) mainAssetWithdraw(withdraw *pt.CrossAssetTransfer, withdrawTx *types.Transaction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
isPara := cfg.IsPara()
//主链处理分支
if !isPara {
return a.execWithdraw(withdraw, withdrawTx)
}
return a.execDestroyAsset(withdraw)
}
func (a *action) paraAssetTransfer(transfer *pt.CrossAssetTransfer) (*types.Receipt, error) {
cfg := a.api.GetConfig()
isPara := cfg.IsPara()
//平行链链处理分支
if isPara {
return a.execTransfer(transfer)
}
return a.execCreateAsset(transfer)
}
//平行链从主链提回, 先在主链处理,然后在平行链处理, 如果平行链执行失败,共识后主链再回滚
func (a *action) paraAssetWithdraw(withdraw *pt.CrossAssetTransfer, withdrawTx *types.Transaction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
isPara := cfg.IsPara()
//平行链链处理分支
if isPara {
return a.execWithdraw(withdraw, withdrawTx)
}
return a.execDestroyAsset(withdraw)
}
func (a *action) execTransfer(transfer *pt.CrossAssetTransfer) (*types.Receipt, error) {
cfg := a.api.GetConfig()
accDB, err := a.createAccount(cfg, a.db, transfer.AssetExec, transfer.AssetSymbol)
if err != nil {
return nil, errors.Wrap(err, "execTransfer.createAccount failed")
}
//平行链处理分支
//主链上存入toAddr为user.p.xx.paracross地址
execAddr := address.ExecAddress(pt.ParaX)
toAddr := address.ExecAddress(string(a.tx.Execer))
//在平行链上存入toAddr为paracross地址
if cfg.IsPara() {
execAddr = address.ExecAddress(string(a.tx.Execer))
toAddr = address.ExecAddress(pt.ParaX)
}
fromAcc := accDB.LoadExecAccount(a.fromaddr, execAddr)
if fromAcc.Balance < transfer.Amount {
return nil, errors.Wrapf(types.ErrNoBalance, "execTransfer,fromBalance=%d", fromAcc.Balance)
}
clog.Debug("paracross.execTransfer", "execer", string(a.tx.Execer), "assetexec", transfer.AssetExec, "symbol", transfer.AssetSymbol,
"txHash", hex.EncodeToString(a.tx.Hash()))
return accDB.ExecTransfer(a.fromaddr, toAddr, execAddr, transfer.Amount)
}
func (a *action) execWithdraw(withdraw *pt.CrossAssetTransfer, withdrawTx *types.Transaction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
accDB, err := a.createAccount(cfg, a.db, withdraw.AssetExec, withdraw.AssetSymbol)
if err != nil {
return nil, errors.Wrap(err, "execWithdraw.createAccount failed")
}
execAddr := address.ExecAddress(pt.ParaX)
fromAddr := address.ExecAddress(string(withdrawTx.Execer))
if cfg.IsPara() {
execAddr = address.ExecAddress(string(withdrawTx.Execer))
fromAddr = address.ExecAddress(pt.ParaX)
}
clog.Debug("Paracross.execWithdraw", "amount", withdraw.Amount, "from", fromAddr,
"assetExec", withdraw.AssetExec, "symbol", withdraw.AssetSymbol, "execAddr", execAddr, "txHash", hex.EncodeToString(a.tx.Hash()))
return accDB.ExecTransfer(fromAddr, withdraw.ToAddr, execAddr, withdraw.Amount)
}
func (a *action) execCreateAsset(transfer *pt.CrossAssetTransfer) (*types.Receipt, error) {
cfg := a.api.GetConfig()
paraTitle, err := getTitleFrom(a.tx.Execer)
if err != nil {
return nil, errors.Wrap(err, "assetTransferCoins call getTitleFrom failed")
return nil, errors.Wrapf(err, "execCreateAsset call getTitleFrom failed,exec=%s", string(a.tx.Execer))
}
assetExec := transfer.AssetExec
assetSymbol := transfer.AssetSymbol
if assetSymbol == "" {
assetExec = coins.CoinsX
assetSymbol = SYMBOL_BTY
} else if assetExec == "" {
assetExec = token.TokenX
}
var paraAcc *account.DB
if transfer.Cointoken == "" {
paraAcc, err = NewParaAccount(cfg, string(paraTitle), "coins", "bty", a.db)
} else {
paraAcc, err = NewParaAccount(cfg, string(paraTitle), "token", transfer.Cointoken, a.db)
if !cfg.IsPara() {
assetExec = string(paraTitle) + assetExec
}
paraAcc, err := NewParaAccount(cfg, string(paraTitle), assetExec, assetSymbol, a.db)
if err != nil {
return nil, errors.Wrap(err, "assetTransferCoins call NewParaAccount failed")
return nil, errors.Wrapf(err, "execCreateAsset call NewParaAccount failed,exec=%s,symbol=%s", assetExec, assetSymbol)
}
clog.Debug("paracross.AssetTransfer isPara", "execer", string(a.tx.Execer),
clog.Debug("paracross.execCreateAsset", "execer", string(a.tx.Execer), "assetExec", assetExec, "symbol", assetSymbol,
"txHash", hex.EncodeToString(a.tx.Hash()))
return assetDepositBalance(paraAcc, transfer.To, transfer.Amount)
return assetDepositBalance(paraAcc, transfer.ToAddr, transfer.Amount)
}
func (a *action) assetWithdraw(withdraw *types.AssetsWithdraw, withdrawTx *types.Transaction) (*types.Receipt, error) {
func (a *action) execDestroyAsset(withdraw *pt.CrossAssetTransfer) (*types.Receipt, error) {
cfg := a.api.GetConfig()
isPara := cfg.IsPara()
//主链处理分支
if !isPara {
accDB, err := createAccount(cfg, a.db, withdraw.Cointoken)
if err != nil {
return nil, errors.Wrap(err, "assetWithdrawCoins call account.NewAccountDB failed")
}
fromAddr := address.ExecAddress(string(withdrawTx.Execer))
execAddr := address.ExecAddress(pt.ParaX)
clog.Debug("Paracross.Exec", "AssettWithdraw", withdraw.Amount, "from", fromAddr,
"to", withdraw.To, "exec", execAddr, "withdrawTx execor", string(withdrawTx.Execer))
return accDB.ExecTransfer(fromAddr, withdraw.To, execAddr, withdraw.Amount)
}
//平行链处理分支
paraTitle, err := getTitleFrom(a.tx.Execer)
if err != nil {
return nil, errors.Wrap(err, "assetWithdrawCoins call getTitleFrom failed")
return nil, errors.Wrap(err, "execDestroyAsset call getTitleFrom failed")
}
assetExec := withdraw.AssetExec
assetSymbol := withdraw.AssetSymbol
if assetSymbol == "" {
assetExec = coins.CoinsX
assetSymbol = SYMBOL_BTY
} else if assetExec == "" {
assetExec = token.TokenX
}
var paraAcc *account.DB
if withdraw.Cointoken == "" {
paraAcc, err = NewParaAccount(cfg, string(paraTitle), "coins", "bty", a.db)
} else {
paraAcc, err = NewParaAccount(cfg, string(paraTitle), "token", withdraw.Cointoken, a.db)
if !cfg.IsPara() {
assetExec = string(paraTitle) + assetExec
}
paraAcc, err := NewParaAccount(cfg, string(paraTitle), assetExec, assetSymbol, a.db)
if err != nil {
return nil, errors.Wrap(err, "assetWithdrawCoins call NewParaAccount failed")
return nil, errors.Wrapf(err, "execDestroyAsset call NewParaAccount failed,exec=%s,symbol=%s", assetExec, assetSymbol)
}
clog.Debug("paracross.assetWithdrawCoins isPara", "execer", string(a.tx.Execer),
clog.Debug("paracross.execDestroyAsset", "execer", string(a.tx.Execer), "assetExec", assetExec, "symbol", assetSymbol,
"txHash", hex.EncodeToString(a.tx.Hash()), "from", a.fromaddr, "amount", withdraw.Amount)
return assetWithdrawBalance(paraAcc, a.fromaddr, withdraw.Amount)
}
func (a *action) assetTransferRollback(transfer *types.AssetsTransfer, transferTx *types.Transaction) (*types.Receipt, error) {
//旧的接口,只有主链向平行链转移
func (a *action) assetTransfer(transfer *types.AssetsTransfer) (*types.Receipt, error) {
tr := &pt.CrossAssetTransfer{
AssetSymbol: transfer.Cointoken,
Amount: transfer.Amount,
Note: string(transfer.Note),
ToAddr: transfer.To,
}
return a.mainAssetTransfer(tr)
}
func (a *action) assetWithdraw(withdraw *types.AssetsWithdraw, withdrawTx *types.Transaction) (*types.Receipt, error) {
tr := &pt.CrossAssetTransfer{
AssetExec: withdraw.ExecName,
AssetSymbol: withdraw.Cointoken,
Amount: withdraw.Amount,
Note: string(withdraw.Note),
ToAddr: withdraw.To,
}
//旧的只有主链向平行链转移和withdraw操作,如果cointoken非空,执行器就是token,不会是其他的
if withdraw.Cointoken != "" {
tr.AssetExec = token.TokenX
}
return a.mainAssetWithdraw(tr, withdrawTx)
}
func (a *action) assetTransferRollback(tr *pt.CrossAssetTransfer, transferTx *types.Transaction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
isPara := cfg.IsPara()
//主链处理分支
if !isPara {
accDB, err := createAccount(cfg, a.db, transfer.Cointoken)
transfer := formatTransfer(tr, pt.ParacrossMainTransfer)
accDB, err := a.createAccount(cfg, a.db, transfer.AssetExec, transfer.AssetSymbol)
if err != nil {
return nil, errors.Wrap(err, "assetTransferToken call account.NewAccountDB failed")
return nil, errors.Wrap(err, "assetTransferRollback.createAccount failed")
}
execAddr := address.ExecAddress(pt.ParaX)
fromAcc := address.ExecAddress(string(transferTx.Execer))
......@@ -105,14 +311,37 @@ func (a *action) assetTransferRollback(transfer *types.AssetsTransfer, transferT
return nil, nil
}
func createAccount(cfg *types.Chain33Config, db db.KV, symbol string) (*account.DB, error) {
//平行链从主链withdraw在平行链执行失败,主链恢复数据,主链执行
func (a *action) paraAssetWithdrawRollback(wtw *pt.CrossAssetTransfer, withdrawTx *types.Transaction) (*types.Receipt, error) {
cfg := a.api.GetConfig()
isPara := cfg.IsPara()
//主链处理分支
if !isPara {
withdraw := formatTransfer(wtw, pt.ParacrossParaWithdraw)
paraTitle, err := getTitleFrom(a.tx.Execer)
if err != nil {
return nil, errors.Wrap(err, "paraAssetWithdrawRollback call getTitleFrom failed")
}
var paraAcc *account.DB
paraAcc, err = NewParaAccount(cfg, string(paraTitle), string(paraTitle)+withdraw.AssetExec, withdraw.AssetSymbol, a.db)
if err != nil {
return nil, errors.Wrap(err, "paraAssetWithdrawRollback call NewParaAccount failed")
}
clog.Debug("paracross.paraAssetWithdrawRollback", "execer", string(a.tx.Execer), "txHash", hex.EncodeToString(a.tx.Hash()))
return assetDepositBalance(paraAcc, withdrawTx.From(), withdraw.Amount)
}
return nil, nil
}
func (a *action) createAccount(cfg *types.Chain33Config, db db.KV, exec, symbol string) (*account.DB, error) {
var accDB *account.DB
var err error
if symbol == "" {
accDB = account.NewCoinsAccount(cfg)
accDB.SetDB(db)
} else {
accDB, err = account.NewAccountDB(cfg, "token", symbol, db)
return accDB, nil
}
if exec == "" {
exec = token.TokenX
}
return accDB, err
return account.NewAccountDB(cfg, exec, symbol, db)
}
......@@ -42,7 +42,6 @@ func (e *Paracross) Exec_AssetTransfer(payload *types.AssetsTransfer, tx *types.
//Exec_AssetWithdraw asset withdraw exec process
func (e *Paracross) Exec_AssetWithdraw(payload *types.AssetsWithdraw, tx *types.Transaction, index int) (*types.Receipt, error) {
clog.Debug("Paracross.Exec", "withdraw", "")
_, err := e.checkTxGroup(tx, index)
if err != nil {
clog.Error("ParacrossActionAssetWithdraw", "get tx group failed", err, "hash", hex.EncodeToString(tx.Hash()))
......@@ -57,6 +56,22 @@ func (e *Paracross) Exec_AssetWithdraw(payload *types.AssetsWithdraw, tx *types.
return receipt, nil
}
//Exec_ParaAssetTransfer parallel chain asset transfer exec process
func (e *Paracross) Exec_CrossAssetTransfer(payload *pt.CrossAssetTransfer, tx *types.Transaction, index int) (*types.Receipt, error) {
_, err := e.checkTxGroup(tx, index)
if err != nil {
clog.Error("ParacrossActionCrossAssetTransfer", "get tx group failed", err, "hash", hex.EncodeToString(tx.Hash()))
return nil, err
}
a := newAction(e, tx)
receipt, err := a.CrossAssetTransfer(payload)
if err != nil {
clog.Error("Paracross CrossAssetTransfer failed", "error", err, "hash", hex.EncodeToString(tx.Hash()))
return nil, errors.Cause(err)
}
return receipt, nil
}
//Exec_Miner miner tx exec process
func (e *Paracross) Exec_Miner(payload *pt.ParacrossMinerAction, tx *types.Transaction, index int) (*types.Receipt, error) {
if index != 0 {
......
......@@ -145,7 +145,7 @@ func (e *Paracross) ExecDelLocal_AssetTransfer(payload *types.AssetsTransfer, tx
// 主链转出记录,
// 转入在 commit done 时记录, 因为没有日志里没有当时tx信息
r, err := e.initLocalAssetTransfer(tx, true, true)
r, err := e.initLocalAssetTransfer(tx, true, nil)
if err != nil {
return nil, err
}
......@@ -159,6 +159,18 @@ func (e *Paracross) ExecDelLocal_AssetWithdraw(payload *types.AssetsWithdraw, tx
return nil, nil
}
//ExecDelLocal_AssetTransfer asset transfer del local db process
func (e *Paracross) ExecDelLocal_CrossAssetTransfer(payload *pt.CrossAssetTransfer, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
var set types.LocalDBSet
r, err := e.initLocalAssetTransfer(tx, true, nil)
if err != nil {
return nil, err
}
set.KV = append(set.KV, r)
return &set, nil
}
//ExecDelLocal_Miner miner tx del local db process
func (e *Paracross) ExecDelLocal_Miner(payload *pt.ParacrossMinerAction, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if index != 0 {
......
......@@ -148,7 +148,11 @@ func (e *Paracross) ExecLocal_AssetTransfer(payload *types.AssetsTransfer, tx *t
// 主链转出记录,
// 转入在 commit done 时记录, 因为没有日志里没有当时tx信息
r, err := e.initLocalAssetTransfer(tx, true, false)
asset, err := e.getAssetTransferInfo(tx, payload.Cointoken, false)
if err != nil {
return nil, err
}
r, err := e.initLocalAssetTransfer(tx, false, asset)
if err != nil {
return nil, err
}
......@@ -162,6 +166,33 @@ func (e *Paracross) ExecLocal_AssetWithdraw(payload *types.AssetsWithdraw, tx *t
return nil, nil
}
//ExecLocal_AssetTransfer asset transfer local proc
func (e *Paracross) ExecLocal_CrossAssetTransfer(payload *pt.CrossAssetTransfer, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
var set types.LocalDBSet
cfg := e.GetAPI().GetConfig()
act, err := getCrossAction(payload, string(tx.Execer))
if err != nil {
clog.Crit("local CrossAssetTransfer getCrossAction failed", "error", err)
return nil, err
}
// 主链转出和平行链提取记录,
// 主链提取和平行链转出在 commit done 时记录
if !cfg.IsPara() && (act == pt.ParacrossMainWithdraw || act == pt.ParacrossParaTransfer) {
return nil, nil
}
asset, err := e.getCrossAssetTransferInfo(payload, tx)
if err != nil {
return nil, err
}
r, err := e.initLocalAssetTransfer(tx, false, asset)
if err != nil {
return nil, err
}
set.KV = append(set.KV, r)
return &set, nil
}
func setMinerTxResult(cfg *types.Chain33Config, payload *pt.ParacrossMinerAction, txs []*types.Transaction, receipts []*types.ReceiptData) error {
isCommitTx := make(map[string]bool)
var curTxHashs, paraTxHashs, crossTxHashs [][]byte
......
......@@ -8,12 +8,12 @@ import (
"bytes"
"encoding/hex"
"github.com/33cn/chain33/common"
log "github.com/33cn/chain33/common/log/log15"
drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
"github.com/pkg/errors"
)
var (
......@@ -135,14 +135,46 @@ func (c *Paracross) udpateLocalParaTxs(paraTitle string, paraHeight int64, cross
hex.EncodeToString(crossTxHashs[i]))
return nil, err
}
if payload.Ty == pt.ParacrossActionCrossAssetTransfer {
act, err := getCrossAction(payload.GetCrossAssetTransfer(), string(paraTx.Tx.Execer))
if err != nil {
clog.Crit("udpateLocalParaTxs getCrossAction failed", "error", err)
return nil, err
}
//主链共识后,平行链执行出错的主链资产transfer回滚
if act == pt.ParacrossMainTransfer || act == pt.ParacrossParaWithdraw {
kv, err := c.updateLocalAssetTransfer(paraTx.Tx, paraHeight, success, isDel)
if err != nil {
return nil, err
}
set.KV = append(set.KV, kv)
}
//主链共识后,平行链执行出错的平行链资产withdraw回滚
if act == pt.ParacrossMainWithdraw || act == pt.ParacrossParaTransfer {
asset, err := c.getCrossAssetTransferInfo(payload.GetCrossAssetTransfer(), paraTx.Tx)
if err != nil {
return nil, err
}
kv, err := c.initLocalAssetTransferDone(paraTx.Tx, asset, paraHeight, success, isDel)
if err != nil {
return nil, err
}
set.KV = append(set.KV, kv)
}
}
if payload.Ty == pt.ParacrossActionAssetTransfer {
kv, err := c.updateLocalAssetTransfer(paraHeight, paraTx.Tx, success, isDel)
kv, err := c.updateLocalAssetTransfer(paraTx.Tx, paraHeight, success, isDel)
if err != nil {
return nil, err
}
set.KV = append(set.KV, kv)
} else if payload.Ty == pt.ParacrossActionAssetWithdraw {
kv, err := c.initLocalAssetWithdraw(paraHeight, paraTx.Tx, true, success, isDel)
asset, err := c.getAssetTransferInfo(paraTx.Tx, payload.GetAssetWithdraw().Cointoken, true)
if err != nil {
return nil, err
}
kv, err := c.initLocalAssetTransferDone(paraTx.Tx, asset, paraHeight, success, isDel)
if err != nil {
return nil, err
}
......@@ -153,105 +185,90 @@ func (c *Paracross) udpateLocalParaTxs(paraTitle string, paraHeight int64, cross
return &set, nil
}
func (c *Paracross) initLocalAssetTransfer(tx *types.Transaction, success, isDel bool) (*types.KeyValue, error) {
clog.Debug("para execLocal", "tx hash", hex.EncodeToString(tx.Hash()), "action name", log.Lazy{Fn: tx.ActionName})
key := calcLocalAssetKey(tx.Hash())
if isDel {
c.GetLocalDB().Set(key, nil)
return &types.KeyValue{Key: key, Value: nil}, nil
}
var payload pt.ParacrossAction
err := types.Decode(tx.Payload, &payload)
if err != nil {
return nil, err
}
if payload.GetAssetTransfer() == nil {
return nil, errors.New("GetAssetTransfer is nil")
}
func (c *Paracross) getAssetTransferInfo(tx *types.Transaction, coinToken string, isWithdraw bool) (*pt.ParacrossAsset, error) {
exec := "coins"
symbol := types.BTY
if payload.GetAssetTransfer().Cointoken != "" {
if coinToken != "" {
exec = "token"
symbol = payload.GetAssetTransfer().Cointoken
symbol = coinToken
}
var asset pt.ParacrossAsset
amount, err := tx.Amount()
if err != nil {
return nil, err
}
asset = pt.ParacrossAsset{
asset := &pt.ParacrossAsset{
From: tx.From(),
To: tx.To,
Amount: amount,
IsWithdraw: false,
TxHash: tx.Hash(),
IsWithdraw: isWithdraw,
TxHash: common.ToHex(tx.Hash()),
Height: c.GetHeight(),
Exec: exec,
Symbol: symbol,
}
return asset, nil
}
err = c.GetLocalDB().Set(key, types.Encode(&asset))
func (c *Paracross) getCrossAssetTransferInfo(payload *pt.CrossAssetTransfer, tx *types.Transaction) (*pt.ParacrossAsset, error) {
exec := payload.AssetExec
symbol := payload.AssetSymbol
if payload.AssetSymbol == "" {
symbol = types.BTY
exec = "coins"
}
amount, err := tx.Amount()
if err != nil {
clog.Error("para execLocal", "set", hex.EncodeToString(tx.Hash()), "failed", err)
return nil, err
}
return &types.KeyValue{Key: key, Value: types.Encode(&asset)}, nil
asset := &pt.ParacrossAsset{
From: tx.From(),
To: tx.To,
Amount: amount,
TxHash: common.ToHex(tx.Hash()),
Height: c.GetHeight(),
Exec: exec,
Symbol: symbol,
}
return asset, nil
}
func (c *Paracross) initLocalAssetWithdraw(paraHeight int64, tx *types.Transaction, isWithdraw, success, isDel bool) (*types.KeyValue, error) {
func (c *Paracross) initLocalAssetTransfer(tx *types.Transaction, isDel bool, asset *pt.ParacrossAsset) (*types.KeyValue, error) {
clog.Debug("para execLocal", "tx hash", hex.EncodeToString(tx.Hash()), "action name", log.Lazy{Fn: tx.ActionName})
key := calcLocalAssetKey(tx.Hash())
if isDel {
c.GetLocalDB().Set(key, nil)
return &types.KeyValue{Key: key, Value: nil}, nil
}
var asset pt.ParacrossAsset
amount, err := tx.Amount()
err := c.GetLocalDB().Set(key, types.Encode(asset))
if err != nil {
return nil, err
}
asset.ParaHeight = paraHeight
var payload pt.ParacrossAction
err = types.Decode(tx.Payload, &payload)
if err != nil {
return nil, err
}
if payload.GetAssetWithdraw() == nil {
return nil, errors.New("GetAssetWithdraw is nil")
}
exec := "coins"
symbol := types.BTY
if payload.GetAssetWithdraw().Cointoken != "" {
exec = "token"
symbol = payload.GetAssetWithdraw().Cointoken
clog.Error("para execLocal", "set", hex.EncodeToString(tx.Hash()), "failed", err)
}
return &types.KeyValue{Key: key, Value: types.Encode(asset)}, nil
}
asset = pt.ParacrossAsset{
From: tx.From(),
To: tx.To,
Amount: amount,
IsWithdraw: isWithdraw,
TxHash: tx.Hash(),
Height: c.GetHeight(),
Exec: exec,
Symbol: symbol,
func (c *Paracross) initLocalAssetTransferDone(tx *types.Transaction, asset *pt.ParacrossAsset, paraHeight int64, success, isDel bool) (*types.KeyValue, error) {
key := calcLocalAssetKey(tx.Hash())
if isDel {
c.GetLocalDB().Set(key, nil)
return &types.KeyValue{Key: key, Value: nil}, nil
}
asset.ParaHeight = paraHeight
asset.CommitDoneHeight = c.GetHeight()
asset.Success = success
err = c.GetLocalDB().Set(key, types.Encode(&asset))
err := c.GetLocalDB().Set(key, types.Encode(asset))
if err != nil {
clog.Error("para execLocal", "set", "", "failed", err)
}
return &types.KeyValue{Key: key, Value: types.Encode(&asset)}, nil
return &types.KeyValue{Key: key, Value: types.Encode(asset)}, nil
}
func (c *Paracross) updateLocalAssetTransfer(paraHeight int64, tx *types.Transaction, success, isDel bool) (*types.KeyValue, error) {
func (c *Paracross) updateLocalAssetTransfer(tx *types.Transaction, paraHeight int64, success, isDel bool) (*types.KeyValue, error) {
clog.Debug("para execLocal", "tx hash", hex.EncodeToString(tx.Hash()))
key := calcLocalAssetKey(tx.Hash())
......@@ -317,6 +334,11 @@ func (c *Paracross) allow(tx *types.Transaction, index int) error {
return nil
}
}
if cfg.IsDappFork(c.GetHeight(), pt.ParaX, pt.ForkParaAssetTransferRbk) {
if payload.Ty == pt.ParacrossActionCrossAssetTransfer {
return nil
}
}
}
return types.ErrNotAllow
}
......
......@@ -441,28 +441,7 @@ func (p *Paracross) paracrossGetAssetTxResult(hash []byte) (types.Message, error
return nil, err
}
rsp := &pt.ParacrossAssetRsp{
From: rst.From,
To: rst.To,
Amount: rst.Amount,
Exec: rst.Exec,
Symbol: rst.Symbol,
Height: rst.Height,
CommitDoneHeight: rst.CommitDoneHeight,
ParaHeight: rst.ParaHeight,
}
rsp.TxHash = common.ToHex(rst.TxHash)
rsp.IsWithdraw = "false"
if rst.IsWithdraw {
rsp.IsWithdraw = "true"
}
rsp.Success = "false"
if rst.Success {
rsp.Success = "true"
}
return rsp, nil
return &rst, nil
}
//Query_GetSelfConsStages get self consensus stages configed
......
......@@ -268,6 +268,15 @@ message ParacrossMinerAction {
bool isSelfConsensus = 2;
}
message CrossAssetTransfer {
uint32 type = 1;
string assetExec = 2;
string assetSymbol = 3;
int64 amount = 4;
string toAddr = 5;
string note = 6;
}
message ParacrossAction {
oneof value {
ParacrossCommitAction commit = 1;
......@@ -280,6 +289,7 @@ message ParacrossAction {
ParaNodeAddrConfig nodeConfig = 9;
ParaNodeGroupConfig nodeGroupConfig = 10;
ParaStageConfig selfStageConfig = 11;
CrossAssetTransfer crossAssetTransfer = 12;
}
int32 ty = 2;
}
......@@ -359,10 +369,12 @@ message ParacrossAsset {
string from = 1;
string to = 2;
bool isWithdraw = 3;
bytes txHash = 4;
string txHash = 4;
int64 amount = 5;
string exec = 6;
string symbol = 7;
//跨链类型 0:to para, 1:to main
uint32 crossType = 8;
// 主链部分
int64 height = 10;
// 平行链部分
......@@ -371,22 +383,6 @@ message ParacrossAsset {
bool success = 23;
}
message ParacrossAssetRsp {
// input
string from = 1;
string to = 2;
string isWithdraw = 3;
string txHash = 4;
int64 amount = 5;
string exec = 6;
string symbol = 7;
// 主链部分
int64 height = 10;
// 平行链部分
int64 commitDoneHeight = 21;
int64 paraHeight = 22;
string success = 23;
}
message ParaLocalDbBlock {
int64 height = 1;
......
......@@ -46,6 +46,8 @@ const (
TyLogParaSelfConsStageConfig = 665
TyLogParaStageVoteDone = 666
TyLogParaStageGroupUpdate = 667
//TyLogParaCrossAssetTransfer 统一的跨链资产转移
TyLogParaCrossAssetTransfer = 670
)
type paracrossCommitTx struct {
......@@ -73,9 +75,9 @@ const (
)
const (
// ParacrossActionAssetTransfer paracross asset transfer key
// ParacrossActionAssetTransfer mainchain paracross asset transfer key
ParacrossActionAssetTransfer = iota + paraCrossTransferActionTypeStart
// ParacrossActionAssetWithdraw paracross asset withdraw key
// ParacrossActionAssetWithdraw mainchain paracross asset withdraw key
ParacrossActionAssetWithdraw
//ParacrossActionNodeConfig para super node config
ParacrossActionNodeConfig
......@@ -83,6 +85,16 @@ const (
ParacrossActionNodeGroupApply
//ParacrossActionSelfConsensStageConfig apply for self consensus stage config
ParacrossActionSelfStageConfig
// ParacrossActionCrossAssetTransfer crossChain asset transfer key
ParacrossActionCrossAssetTransfer
)
const (
ParacrossNoneTransfer = iota
ParacrossMainTransfer
ParacrossMainWithdraw
ParacrossParaTransfer
ParacrossParaWithdraw
)
// status
......@@ -342,6 +354,21 @@ func (p ParacrossType) CreateRawTransferTx(action string, param json.RawMessage)
return tx, nil
}
//CreateRawCrossAssetTransferTx create raw cross asset transfer tx
func CreateRawCrossAssetTransferTx(apply *CrossAssetTransfer) (*types.Transaction, error) {
action := &ParacrossAction{
Ty: ParacrossActionCrossAssetTransfer,
Value: &ParacrossAction_CrossAssetTransfer{apply},
}
tx := &types.Transaction{
Payload: types.Encode(action),
}
return tx, nil
}
//GetDappForkHeight get paracross dapp fork height
func GetDappForkHeight(cfg *types.Chain33Config, forkKey string) int64 {
var forkHeight int64
......
......@@ -96,6 +96,7 @@ func (p *ParacrossType) GetLogMap() map[int64]*types.LogInfo {
TyLogParaAssetWithdraw: {Ty: reflect.TypeOf(types.ReceiptAccountTransfer{}), Name: "LogParaAssetWithdraw"},
TyLogParaAssetTransfer: {Ty: reflect.TypeOf(types.ReceiptAccountTransfer{}), Name: "LogParaAssetTransfer"},
TyLogParaAssetDeposit: {Ty: reflect.TypeOf(types.ReceiptAccountTransfer{}), Name: "LogParaAssetDeposit"},
TyLogParaCrossAssetTransfer: {Ty: reflect.TypeOf(types.ReceiptAccountTransfer{}), Name: "LogParaCrossAssetTransfer"},
TyLogParacrossMiner: {Ty: reflect.TypeOf(ReceiptParacrossMiner{}), Name: "LogParacrossMiner"},
TyLogParaNodeConfig: {Ty: reflect.TypeOf(ReceiptParaNodeConfig{}), Name: "LogParaNodeConfig"},
TyLogParaNodeStatusUpdate: {Ty: reflect.TypeOf(ReceiptParaNodeAddrStatUpdate{}), Name: "LogParaNodeAddrStatUpdate"},
......@@ -112,16 +113,17 @@ func (p *ParacrossType) GetLogMap() map[int64]*types.LogInfo {
// GetTypeMap get action type
func (p *ParacrossType) GetTypeMap() map[string]int32 {
return map[string]int32{
"Commit": ParacrossActionCommit,
"Miner": ParacrossActionMiner,
"AssetTransfer": ParacrossActionAssetTransfer,
"AssetWithdraw": ParacrossActionAssetWithdraw,
"Transfer": ParacrossActionTransfer,
"Withdraw": ParacrossActionWithdraw,
"TransferToExec": ParacrossActionTransferToExec,
"NodeConfig": ParacrossActionNodeConfig,
"NodeGroupConfig": ParacrossActionNodeGroupApply,
"SelfStageConfig": ParacrossActionSelfStageConfig,
"Commit": ParacrossActionCommit,
"Miner": ParacrossActionMiner,
"AssetTransfer": ParacrossActionAssetTransfer,
"AssetWithdraw": ParacrossActionAssetWithdraw,
"Transfer": ParacrossActionTransfer,
"Withdraw": ParacrossActionWithdraw,
"TransferToExec": ParacrossActionTransferToExec,
"CrossAssetTransfer": ParacrossActionCrossAssetTransfer,
"NodeConfig": ParacrossActionNodeConfig,
"NodeGroupConfig": ParacrossActionNodeGroupApply,
"SelfStageConfig": ParacrossActionSelfStageConfig,
}
}
......@@ -156,6 +158,14 @@ func (p ParacrossType) CreateTx(action string, message json.RawMessage) (*types.
action == "ParacrossTransferToExec" || action == "TransferToExec" {
return p.CreateRawTransferTx(action, message)
} else if action == "CrossAssetTransfer" {
var param CrossAssetTransfer
err := types.JSONToPB(message, &param)
if err != nil {
glog.Error("CreateTx.CrossAssetTransfer", "Error", err)
return nil, types.ErrInvalidParam
}
return CreateRawCrossAssetTransferTx(&param)
} else if action == "NodeConfig" {
var param ParaNodeAddrConfig
err := types.JSONToPB(message, &param)
......
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