Commit a1c96130 authored by hezhengjun's avatar hezhengjun

add permission process for token withdraw

parent 832075c0
...@@ -1204,16 +1204,20 @@ func addCfgWithdrawFlags(cmd *cobra.Command) { ...@@ -1204,16 +1204,20 @@ func addCfgWithdrawFlags(cmd *cobra.Command) {
_ = cmd.MarkFlagRequired("symbol") _ = cmd.MarkFlagRequired("symbol")
cmd.Flags().Int64P("fee", "f", 0, "fee amount") cmd.Flags().Int64P("fee", "f", 0, "fee amount")
_ = cmd.MarkFlagRequired("fee") _ = cmd.MarkFlagRequired("fee")
cmd.Flags().Int64P("amount", "a", 0, "accumulative amount allowed to be withdrew per day")
_ = cmd.MarkFlagRequired("amount")
} }
func CfgWithdraw(cmd *cobra.Command, _ []string) { func CfgWithdraw(cmd *cobra.Command, _ []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr") rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
symbol, _ := cmd.Flags().GetString("symbol") symbol, _ := cmd.Flags().GetString("symbol")
fee, _ := cmd.Flags().GetInt64("fee") fee, _ := cmd.Flags().GetInt64("fee")
amount, _ := cmd.Flags().GetInt64("amount")
req := &ebTypes.CfgWithdrawReq{ req := &ebTypes.CfgWithdrawReq{
Symbol: symbol, Symbol: symbol,
FeeAmount: fee, FeeAmount: fee,
AmountPerDay: amount,
} }
var res rpctypes.Reply var res rpctypes.Reply
......
...@@ -249,10 +249,30 @@ message ResendChain33EventReq { ...@@ -249,10 +249,30 @@ message ResendChain33EventReq {
message CfgWithdrawReq { message CfgWithdrawReq {
string symbol = 1; string symbol = 1;
int64 feeAmount = 2; int64 feeAmount = 2;
int64 amountPerDay = 3;
} }
message WithdrawSymbol2Fee { message withdrawPara {
map<string, int64> symbol2Fee = 1; int64 fee = 1;
int64 amountPerDay = 2;
}
message WithdrawSymbol2Para {
map<string, withdrawPara> symbol2Para = 1;
}
message WithdrawTx {
string chain33Sender = 1;
string ethereumReceiver = 2;
string symbol = 4;
int64 amount = 5;
int64 nonce = 6;
string txHashOnChain33 = 7;
string txHashOnEthereum = 8;
int32 year = 9;
int32 month = 10;
int32 day = 11;
string status = 12;
} }
......
...@@ -20,6 +20,8 @@ import ( ...@@ -20,6 +20,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
chain33EvmCommon "github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/33cn/plugin/plugin/dapp/cross2eth/ebrelayer/utils" "github.com/33cn/plugin/plugin/dapp/cross2eth/ebrelayer/utils"
dbm "github.com/33cn/chain33/common/db" dbm "github.com/33cn/chain33/common/db"
...@@ -75,7 +77,7 @@ type Relayer4Ethereum struct { ...@@ -75,7 +77,7 @@ type Relayer4Ethereum struct {
symbol2Addr map[string]common.Address symbol2Addr map[string]common.Address
symbol2LockAddr map[string]ebTypes.TokenAddress symbol2LockAddr map[string]ebTypes.TokenAddress
mulSignAddr string mulSignAddr string
withdrawFee map[string]int64 withdrawFee map[string]*ebTypes.WithdrawPara
} }
var ( var (
...@@ -463,7 +465,6 @@ func (ethRelayer *Relayer4Ethereum) proc() { ...@@ -463,7 +465,6 @@ func (ethRelayer *Relayer4Ethereum) proc() {
var timer *time.Ticker var timer *time.Ticker
ctx := context.Background() ctx := context.Background()
continueFailCount := int32(0)
for range ethRelayer.unlockchan { for range ethRelayer.unlockchan {
relayerLog.Info("Received ethRelayer.unlockchan") relayerLog.Info("Received ethRelayer.unlockchan")
ethRelayer.rwLock.RLock() ethRelayer.rwLock.RLock()
...@@ -485,7 +486,7 @@ latter: ...@@ -485,7 +486,7 @@ latter:
for { for {
select { select {
case <-timer.C: case <-timer.C:
ethRelayer.procNewHeight(ctx, &continueFailCount) ethRelayer.procNewHeight(ctx)
case err := <-ethRelayer.bridgeBankSub.Err(): case err := <-ethRelayer.bridgeBankSub.Err():
relayerLog.Error("proc", "bridgeBankSub err", err.Error()) relayerLog.Error("proc", "bridgeBankSub err", err.Error())
ethRelayer.subscribeEvent() ethRelayer.subscribeEvent()
...@@ -508,7 +509,39 @@ func (ethRelayer *Relayer4Ethereum) handleChain33Msg(chain33Msg *events.Chain33M ...@@ -508,7 +509,39 @@ func (ethRelayer *Relayer4Ethereum) handleChain33Msg(chain33Msg *events.Chain33M
return return
} }
type WithdrawTx struct {
Chain33Sender chain33EvmCommon.Address
EthereumReceiver common.Address
TokenContractAddress chain33EvmCommon.Address
Symbol string
Amount *big.Int
TxHash []byte
Nonce int64
year int
month int
day int
}
func (ethRelayer *Relayer4Ethereum) checkPermissionWithinOneDay(withdrawTx *ebTypes.WithdrawTx) (bool, error) {
totalAlready, err := ethRelayer.getWithdrawsWithinSameDay(withdrawTx)
if nil != err {
relayerLog.Error("checkPermissionWithinOneDay", "Failed to getWithdrawsWithinSameDay due to", err.Error())
return false, errors.New("ErrGetWithdrawsWithinSameDay")
}
withdrawPara, ok := ethRelayer.withdrawFee[withdrawTx.Symbol]
if !ok {
relayerLog.Error("checkPermissionWithinOneDay", "No withdraw parameter configured for symbol ", withdrawTx.Symbol)
return false, errors.New("ErrNoWithdrawParaCfged")
}
if totalAlready+withdrawTx.Amount > withdrawPara.AmountPerDay {
relayerLog.Error("checkPermissionWithinOneDay", "No withdraw parameter configured for symbol ", withdrawTx.Symbol)
return false, errors.New("ErrWithdrawAmountTooBig")
}
return true, nil
}
func (ethRelayer *Relayer4Ethereum) handleLogWithdraw(chain33Msg *events.Chain33Msg) { func (ethRelayer *Relayer4Ethereum) handleLogWithdraw(chain33Msg *events.Chain33Msg) {
//只有通过代理人登录的中继器,才处理提币事件
if !ethRelayer.processWithDraw { if !ethRelayer.processWithDraw {
relayerLog.Info("handleLogWithdraw", "Needn't process withdraw for this relay validator", ethRelayer.ethSender) relayerLog.Info("handleLogWithdraw", "Needn't process withdraw for this relay validator", ethRelayer.ethSender)
return return
...@@ -521,6 +554,29 @@ func (ethRelayer *Relayer4Ethereum) handleLogWithdraw(chain33Msg *events.Chain33 ...@@ -521,6 +554,29 @@ func (ethRelayer *Relayer4Ethereum) handleLogWithdraw(chain33Msg *events.Chain33
return return
} }
now := time.Now()
year, month, day := now.Date()
withdrawTx := &ebTypes.WithdrawTx{
Chain33Sender: chain33Msg.Chain33Sender.String(),
EthereumReceiver: chain33Msg.EthereumReceiver.String(),
Symbol: chain33Msg.Symbol,
Amount: chain33Msg.Amount.Int64(),
TxHashOnChain33: common.Bytes2Hex(chain33Msg.TxHash),
Nonce: chain33Msg.Nonce,
Year: int32(year),
Month: int32(month),
Day: int32(day),
}
if ok, err := ethRelayer.checkPermissionWithinOneDay(withdrawTx); !ok {
withdrawTx.Status = err.Error()
err := ethRelayer.setWithdraw(withdrawTx)
if nil != err {
relayerLog.Error("handleLogWithdraw", "Failed to setWithdraw due to:", err.Error())
}
return
}
tokenAddr := common.HexToAddress(withdrawFromChain33TokenInfo.Address) tokenAddr := common.HexToAddress(withdrawFromChain33TokenInfo.Address)
//从chain33进行withdraw回来的token需要根据精度进行相应的缩放 //从chain33进行withdraw回来的token需要根据精度进行相应的缩放
if 8 != withdrawFromChain33TokenInfo.Decimal { if 8 != withdrawFromChain33TokenInfo.Decimal {
...@@ -546,9 +602,19 @@ func (ethRelayer *Relayer4Ethereum) handleLogWithdraw(chain33Msg *events.Chain33 ...@@ -546,9 +602,19 @@ func (ethRelayer *Relayer4Ethereum) handleLogWithdraw(chain33Msg *events.Chain33
"Receiver on Ethereum", chain33Msg.EthereumReceiver.String()) "Receiver on Ethereum", chain33Msg.EthereumReceiver.String())
//TODO:此处需要完成在以太坊发送以太或者ERC20数字资产的操作 //TODO:此处需要完成在以太坊发送以太或者ERC20数字资产的操作
withdrawTx.Status = "Withdraw Tx has been sent to Ethereum"
err := ethRelayer.setWithdraw(withdrawTx)
if nil != err {
relayerLog.Error("handleLogWithdraw", "Failed to setWithdraw due to:", err.Error())
}
return
} }
func (ethRelayer *Relayer4Ethereum) handleLogLockBurn(chain33Msg *events.Chain33Msg) { func (ethRelayer *Relayer4Ethereum) handleLogLockBurn(chain33Msg *events.Chain33Msg) {
//对于通过代理人登录的中继器,不处理lock和burn事件
if ethRelayer.processWithDraw {
relayerLog.Info("handleLogWithdraw", "Needn't process lock and burn for this withdraw process specified validator", ethRelayer.ethSender)
return
}
relayerLog.Info("handleLogLockBurn", "Received chain33Msg", chain33Msg, "tx hash string", common.Bytes2Hex(chain33Msg.TxHash)) relayerLog.Info("handleLogLockBurn", "Received chain33Msg", chain33Msg, "tx hash string", common.Bytes2Hex(chain33Msg.TxHash))
// Parse the Chain33Msg into a ProphecyClaim for relay to Ethereum // Parse the Chain33Msg into a ProphecyClaim for relay to Ethereum
...@@ -648,30 +714,33 @@ func (ethRelayer *Relayer4Ethereum) handleLogLockBurn(chain33Msg *events.Chain33 ...@@ -648,30 +714,33 @@ func (ethRelayer *Relayer4Ethereum) handleLogLockBurn(chain33Msg *events.Chain33
"Chain33Sender", statics.Chain33Sender) "Chain33Sender", statics.Chain33Sender)
} }
func (ethRelayer *Relayer4Ethereum) procNewHeight(ctx context.Context, continueFailCount *int32) { func (ethRelayer *Relayer4Ethereum) getCurrentHeight(ctx context.Context) (uint64, error) {
head, err := ethRelayer.clientSpec.HeaderByNumber(ctx, nil) head, err := ethRelayer.clientSpec.HeaderByNumber(ctx, nil)
if nil != err { if nil == err {
*continueFailCount++ return head.Number.Uint64(), nil
if *continueFailCount >= 5 { }
//TODO: 需要在下面添加报警处理
for {
time.Sleep(5 * time.Second)
ethRelayer.clientSpec, err = ethtxs.SetupWebsocketEthClient(ethRelayer.providerHttp) ethRelayer.clientSpec, err = ethtxs.SetupWebsocketEthClient(ethRelayer.providerHttp)
if err != nil { if err != nil {
relayerLog.Error("SetupWebsocketEthClient", "err", err) relayerLog.Error("getCurrentHeight", "Failed to SetupWebsocketEthClient due to:", err.Error())
return continue
} }
head, err := ethRelayer.clientSpec.HeaderByNumber(ctx, nil)
if nil != err {
relayerLog.Error("getCurrentHeight", "Failed to HeaderByNumber due to:", err.Error())
continue
} }
//retry return head.Number.Uint64(), nil
head, err = ethRelayer.clientSpec.HeaderByNumber(ctx, nil)
if err != nil {
relayerLog.Error("Failed to get ethereum height", "provider", ethRelayer.provider,
"continueFailCount", continueFailCount, "err", err.Error())
return
} }
}
} func (ethRelayer *Relayer4Ethereum) procNewHeight(ctx context.Context) {
currentHeight, _ := ethRelayer.getCurrentHeight(ctx)
ethRelayer.updateTxStatus() ethRelayer.updateTxStatus()
*continueFailCount = 0 //currentHeight := head.Number.Uint64()
currentHeight := head.Number.Uint64()
relayerLog.Info("procNewHeight", "currentHeight", currentHeight, "ethRelayer.eventLogIndex.Height", ethRelayer.eventLogIndex.Height, "uint64(ethRelayer.maturityDegree)", uint64(ethRelayer.maturityDegree)) relayerLog.Info("procNewHeight", "currentHeight", currentHeight, "ethRelayer.eventLogIndex.Height", ethRelayer.eventLogIndex.Height, "uint64(ethRelayer.maturityDegree)", uint64(ethRelayer.maturityDegree))
//一次最大只获取10个logEvent进行处理 //一次最大只获取10个logEvent进行处理
...@@ -795,12 +864,8 @@ func (ethRelayer *Relayer4Ethereum) filterLogEvents() { ...@@ -795,12 +864,8 @@ func (ethRelayer *Relayer4Ethereum) filterLogEvents() {
height4BridgeBankLogAt = deployHeight height4BridgeBankLogAt = deployHeight
} }
header, err := ethRelayer.clientSpec.HeaderByNumber(context.Background(), nil) curHeightUint64, _ := ethRelayer.getCurrentHeight(context.Background())
if err != nil { curHeight := int64(curHeightUint64)
errinfo := fmt.Sprintf("Failed to get HeaderByNumbers due to:%s", err.Error())
panic(errinfo)
}
curHeight := int64(header.Number.Uint64())
relayerLog.Info("filterLogEvents", "curHeight:", curHeight) relayerLog.Info("filterLogEvents", "curHeight:", curHeight)
bridgeBankSig := make(map[string]bool) bridgeBankSig := make(map[string]bool)
...@@ -1133,9 +1198,13 @@ func (ethRelayer *Relayer4Ethereum) SetMultiSignAddr(address string) { ...@@ -1133,9 +1198,13 @@ func (ethRelayer *Relayer4Ethereum) SetMultiSignAddr(address string) {
ethRelayer.setMultiSignAddress(address) ethRelayer.setMultiSignAddress(address)
} }
func (ethRelayer *Relayer4Ethereum) CfgWithdraw(symbol string, feeAmount int64) error { func (ethRelayer *Relayer4Ethereum) CfgWithdraw(symbol string, feeAmount, amountPerDay int64) error {
withdrawPara := &ebTypes.WithdrawPara{
Fee: feeAmount,
AmountPerDay: amountPerDay,
}
ethRelayer.rwLock.Lock() ethRelayer.rwLock.Lock()
ethRelayer.withdrawFee[symbol] = feeAmount ethRelayer.withdrawFee[symbol] = withdrawPara
ethRelayer.rwLock.Unlock() ethRelayer.rwLock.Unlock()
return ethRelayer.setWithdrawFee(ethRelayer.withdrawFee) return ethRelayer.setWithdrawFee(ethRelayer.withdrawFee)
......
...@@ -27,7 +27,8 @@ var ( ...@@ -27,7 +27,8 @@ var (
ethLockTxUpdateTxIndex = []byte("eth-ethLockTxUpdateTxIndex") ethLockTxUpdateTxIndex = []byte("eth-ethLockTxUpdateTxIndex")
ethBurnTxUpdateTxIndex = []byte("eth-ethBurnTxUpdateTxIndex") ethBurnTxUpdateTxIndex = []byte("eth-ethBurnTxUpdateTxIndex")
multiSignAddressPrefix = []byte("eth-multiSignAddress") multiSignAddressPrefix = []byte("eth-multiSignAddress")
withdrawFeeKey = []byte("eth-withdrawFee") withdrawParaKey = []byte("eth-withdrawPara")
withdrawTokenPrefix = []byte("eth-withdrawTokenPrefix")
) )
func ethTokenSymbol2AddrKey(symbol string) []byte { func ethTokenSymbol2AddrKey(symbol string) []byte {
...@@ -385,27 +386,74 @@ func (ethRelayer *Relayer4Ethereum) getMultiSignAddress() string { ...@@ -385,27 +386,74 @@ func (ethRelayer *Relayer4Ethereum) getMultiSignAddress() string {
return string(bytes) return string(bytes)
} }
func (ethRelayer *Relayer4Ethereum) setWithdrawFee(symbol2Fee map[string]int64) error { func (ethRelayer *Relayer4Ethereum) setWithdrawFee(symbol2Para map[string]*ebTypes.WithdrawPara) error {
withdrawSymbol2Fee := &ebTypes.WithdrawSymbol2Fee{ withdrawSymbol2Fee := &ebTypes.WithdrawSymbol2Para{
Symbol2Fee: symbol2Fee, Symbol2Para: symbol2Para,
} }
bytes := chain33Types.Encode(withdrawSymbol2Fee) bytes := chain33Types.Encode(withdrawSymbol2Fee)
return ethRelayer.db.Set(withdrawFeeKey, bytes) return ethRelayer.db.Set(withdrawParaKey, bytes)
} }
func (ethRelayer *Relayer4Ethereum) restoreWithdrawFee() map[string]int64 { func (ethRelayer *Relayer4Ethereum) restoreWithdrawFee() map[string]*ebTypes.WithdrawPara {
bytes, _ := ethRelayer.db.Get(withdrawFeeKey) bytes, _ := ethRelayer.db.Get(withdrawParaKey)
if 0 == len(bytes) { if 0 == len(bytes) {
result := make(map[string]int64) result := make(map[string]*ebTypes.WithdrawPara)
return result return result
} }
var withdrawSymbol2Fee ebTypes.WithdrawSymbol2Fee var withdrawSymbol2Para ebTypes.WithdrawSymbol2Para
if err := chain33Types.Decode(bytes, &withdrawSymbol2Fee); nil != err { if err := chain33Types.Decode(bytes, &withdrawSymbol2Para); nil != err {
result := make(map[string]int64) result := make(map[string]*ebTypes.WithdrawPara)
return result return result
} }
return withdrawSymbol2Fee.Symbol2Fee return withdrawSymbol2Para.Symbol2Para
}
func calcWithdrawKey(chain33Sender, symbol string, year, month, day int, nonce int64) []byte {
return []byte(fmt.Sprintf("%s-%s-%s-%d-%d-%d-%d", withdrawTokenPrefix, chain33Sender, symbol, year, month, day, nonce))
}
func calcWithdrawKeyPrefix(chain33Sender, symbol string, year, month, day int) []byte {
return []byte(fmt.Sprintf("%s-%s-%s-%d-%d-%d", withdrawTokenPrefix, chain33Sender, symbol, year, month, day))
}
func (ethRelayer *Relayer4Ethereum) setWithdraw(withdrawTx *ebTypes.WithdrawTx) error {
chain33Sender := withdrawTx.Chain33Sender
symbol := withdrawTx.Symbol
year := withdrawTx.Year
month := withdrawTx.Month
day := withdrawTx.Day
key := calcWithdrawKey(chain33Sender, symbol, int(year), int(month), int(day), withdrawTx.Nonce)
bytes := chain33Types.Encode(withdrawTx)
return ethRelayer.db.Set(key, bytes)
}
func (ethRelayer *Relayer4Ethereum) getWithdrawsWithinSameDay(withdrawTx *ebTypes.WithdrawTx) (int64, error) {
chain33Sender := withdrawTx.Chain33Sender
symbol := withdrawTx.Symbol
year := withdrawTx.Year
month := withdrawTx.Month
day := withdrawTx.Day
prefix := calcWithdrawKeyPrefix(chain33Sender, symbol, int(year), int(month), int(day))
helper := dbm.NewListHelper(ethRelayer.db)
datas := helper.List(prefix, nil, 100, dbm.ListASC)
if nil == datas {
return 0, nil
}
withdrawTotal := int64(0)
for _, data := range datas {
var info ebTypes.WithdrawTx
err := chain33Types.Decode(data, &info)
if nil != err {
return 0, err
}
withdrawTotal += info.Amount
}
return withdrawTotal, nil
} }
...@@ -1109,7 +1109,7 @@ func (manager *Manager) CfgWithdraw(cfgWithdrawReq *relayerTypes.CfgWithdrawReq, ...@@ -1109,7 +1109,7 @@ func (manager *Manager) CfgWithdraw(cfgWithdrawReq *relayerTypes.CfgWithdrawReq,
if err := manager.checkPermission(); nil != err { if err := manager.checkPermission(); nil != err {
return err return err
} }
err := manager.ethRelayer.CfgWithdraw(cfgWithdrawReq.Symbol, cfgWithdrawReq.FeeAmount) err := manager.ethRelayer.CfgWithdraw(cfgWithdrawReq.Symbol, cfgWithdrawReq.FeeAmount, cfgWithdrawReq.AmountPerDay)
resultCfg := true resultCfg := true
if err != nil { if err != nil {
resultCfg = false resultCfg = false
......
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