Commit 34fd2055 authored by whisker's avatar whisker

refactor x2ethereum contract

parent 98a98728
......@@ -94,9 +94,6 @@ func addEth2Chain33Flags(cmd *cobra.Command) {
cmd.Flags().Int64("claimtype", 0, "the type of this claim,lock=1,burn=2")
_ = cmd.MarkFlagRequired("claimtype")
cmd.Flags().Int64("decimal", 0, "the decimal of this token")
_ = cmd.MarkFlagRequired("decimal")
}
func Eth2Chain33(cmd *cobra.Command, args []string) {
......@@ -111,7 +108,13 @@ func Eth2Chain33(cmd *cobra.Command, args []string) {
validator, _ := cmd.Flags().GetString("validator")
amount, _ := cmd.Flags().GetFloat64("amount")
claimtype, _ := cmd.Flags().GetInt64("claimtype")
decimal, _ := cmd.Flags().GetInt64("decimal")
nodeAddr, _ := cmd.Flags().GetString("node_addr")
decimal, err := utils.GetDecimalsFromNode(tcontract, nodeAddr)
if err != nil {
fmt.Println("get decimal error")
return
}
params := &types3.Eth2Chain33{
EthereumChainID: ethid,
......@@ -123,7 +126,7 @@ func Eth2Chain33(cmd *cobra.Command, args []string) {
EthereumSender: sender,
Chain33Receiver: receiver,
ValidatorAddress: validator,
Amount: strconv.FormatFloat(types3.MultiplySpecifyTimes(amount, decimal), 'f', 4, 64),
Amount: strconv.FormatFloat(amount*1e8, 'f', 4, 64),
ClaimType: claimtype,
Decimals: decimal,
}
......@@ -157,7 +160,13 @@ func WithdrawEth(cmd *cobra.Command, args []string) {
validator, _ := cmd.Flags().GetString("validator")
amount, _ := cmd.Flags().GetFloat64("amount")
claimtype, _ := cmd.Flags().GetInt64("claimtype")
decimal, _ := cmd.Flags().GetInt64("decimal")
nodeAddr, _ := cmd.Flags().GetString("node_addr")
decimal, err := utils.GetDecimalsFromNode(tcontract, nodeAddr)
if err != nil {
fmt.Println("get decimal error")
return
}
params := &types3.Eth2Chain33{
EthereumChainID: ethid,
......@@ -226,7 +235,7 @@ func burn(cmd *cobra.Command, args []string) {
params := &types3.Chain33ToEth{
TokenContract: contract,
EthereumReceiver: receiver,
Amount: types3.TrimZeroAndDot(strconv.FormatFloat(types3.MultiplySpecifyTimes(amount, decimal), 'f', 4, 64)),
Amount: types3.TrimZeroAndDot(strconv.FormatFloat(amount*1e8, 'f', 4, 64)),
LocalCoinSymbol: csymbol,
Decimals: decimal,
}
......@@ -319,7 +328,7 @@ func CreateRawAddValidatorTxCmd() *cobra.Command {
}
addValidatorFlags(cmd)
cmd.Flags().Int64P("power", "p", 0, "validator power set")
cmd.Flags().Int64P("power", "p", 0, "validator power set,must be 1-100")
_ = cmd.MarkFlagRequired("power")
return cmd
}
......@@ -377,7 +386,7 @@ func CreateRawModifyValidatorTxCmd() *cobra.Command {
addValidatorFlags(cmd)
cmd.Flags().Int64P("power", "p", 0, "validator power set")
cmd.Flags().Int64P("power", "p", 0, "validator power set,must be 1-100")
_ = cmd.MarkFlagRequired("power")
return cmd
}
......@@ -409,7 +418,7 @@ func CreateRawSetConsensusTxCmd() *cobra.Command {
}
func addSetConsensusFlags(cmd *cobra.Command) {
cmd.Flags().Int64P("power", "p", 0, "the power you want to set consensus need")
cmd.Flags().Int64P("power", "p", 0, "the power you want to set consensus need,must be 1-100")
_ = cmd.MarkFlagRequired("power")
}
......
......@@ -122,7 +122,7 @@ func queryConsensus(cmd *cobra.Command, args []string) {
FuncName: types2.FuncQueryConsensusThreshold,
}
channel := &types2.ReceiptSetConsensusThreshold{}
channel := &types2.ReceiptQueryConsensusThreshold{}
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.Query", query, channel)
ctx.Run()
}
......
......@@ -13,9 +13,6 @@ import (
"github.com/spf13/cobra"
)
// todo
// 所有amount要做bigint处理,还要做只保留四位的截断处理
// EthereumRelayerCmd command func
func EthereumRelayerCmd() *cobra.Command {
cmd := &cobra.Command{
......
......@@ -42,6 +42,12 @@ func LogLockToEthBridgeClaim(event *events.LockEvent, ethereumChainID int64, bri
witnessClaim.Symbol = event.Symbol
witnessClaim.EthereumSender = event.From.String()
witnessClaim.Chain33Receiver = string(recipient)
if decimal > 8 {
event.Value = event.Value.Quo(event.Value, big.NewInt(int64(types.MultiplySpecifyTimes(1, decimal-8))))
} else {
event.Value = event.Value.Mul(event.Value, big.NewInt(int64(types.MultiplySpecifyTimes(1, 8-decimal))))
}
witnessClaim.Amount = event.Value.String()
witnessClaim.ClaimType = types.LOCK_CLAIM_TYPE
......@@ -97,6 +103,11 @@ func ParseBurnLockTxReceipt(claimType events.Event, receipt *chain33Types.Receip
chain33ToEth.Amount = types.TrimZeroAndDot(chain33ToEth.Amount)
amount = big.NewInt(1)
amount, _ = amount.SetString(chain33ToEth.Amount, 10)
if chain33ToEth.Decimals > 8 {
amount = amount.Mul(amount, big.NewInt(int64(types.MultiplySpecifyTimes(1, chain33ToEth.Decimals-8))))
} else {
amount = amount.Quo(amount, big.NewInt(int64(types.MultiplySpecifyTimes(1, 8-chain33ToEth.Decimals))))
}
txslog.Info("ParseBurnLockTxReceipt", "chain33Sender", chain33Sender, "ethereumReceiver", ethereumReceiver.String(), "tokenContractAddress", tokenContractAddress.String(), "symbol", symbol, "amount", amount.String())
// Package the event data into a Chain33Msg
......
package common
import (
"fmt"
"reflect"
gethCommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
// EthereumAddress defines a standard ethereum address
type EthAddress gethCommon.Address
// NewEthereumAddress is a constructor function for EthereumAddress
func NewEthereumAddress(address string) EthAddress {
return EthAddress(gethCommon.HexToAddress(address))
}
// Route should return the name of the module
func (ethAddr EthAddress) String() string {
return gethCommon.Address(ethAddr).String()
}
// MarshalJSON marshals the etherum address to JSON
func (ethAddr EthAddress) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%v\"", ethAddr.String())), nil
}
// UnmarshalJSON unmarshals an ethereum address
func (ethAddr *EthAddress) UnmarshalJSON(input []byte) error {
return hexutil.UnmarshalFixedJSON(reflect.TypeOf(gethCommon.Address{}), input, ethAddr[:])
}
package common
import (
"fmt"
"math"
"math/big"
"testing"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
)
func TestAddToStringMap(t *testing.T) {
bn := big.NewInt(1)
ss := types.TrimZeroAndDot(fmt.Sprintf("%.0f", types.MultiplySpecifyTimes(math.Trunc(5*1e4), 14)))
bn, ok := bn.SetString(ss, 10)
fmt.Println(bn, ok)
}
package ethbridge
import (
"encoding/json"
"errors"
"fmt"
"github.com/golang/protobuf/proto"
"strconv"
log "github.com/33cn/chain33/common/log/log15"
......@@ -15,22 +15,6 @@ var (
elog = log.New("module", "ethbridge")
)
func NewEthBridgeClaim(ethereumChainID int64, bridgeContract string, nonce int64, localCoinSymbol, localCoinExec string, tokenContact string, ethereumSender string, chain33Receiver string, validator string, amount string, claimType int64) types.Eth2Chain33 {
return types.Eth2Chain33{
EthereumChainID: ethereumChainID,
BridgeContractAddress: bridgeContract,
Nonce: nonce,
TokenContractAddress: tokenContact,
EthereumSender: ethereumSender,
Chain33Receiver: chain33Receiver,
ValidatorAddress: validator,
Amount: amount,
ClaimType: claimType,
LocalCoinSymbol: localCoinSymbol,
LocalCoinExec: localCoinExec,
}
}
func NewOracleClaimContent(chain33Receiver string, amount string, claimType, decimals int64) types.OracleClaimContent {
return types.OracleClaimContent{
Chain33Receiver: chain33Receiver,
......@@ -53,14 +37,14 @@ func CreateOracleClaimFromEthClaim(ethClaim types.Eth2Chain33) (types.OracleClai
if ethClaim.ClaimType != int64(types.LOCK_CLAIM_TYPE) && ethClaim.ClaimType != int64(types.BURN_CLAIM_TYPE) {
return types.OracleClaim{}, types.ErrInvalidClaimType
}
oracleID := strconv.Itoa(int(ethClaim.EthereumChainID)) + strconv.Itoa(int(ethClaim.Nonce)) + ethClaim.EthereumSender
oracleID := strconv.Itoa(int(ethClaim.EthereumChainID)) + strconv.Itoa(int(ethClaim.Nonce)) + ethClaim.EthereumSender + ethClaim.TokenContractAddress
if ethClaim.ClaimType == int64(types.LOCK_CLAIM_TYPE) {
oracleID = oracleID + "lock"
} else if ethClaim.ClaimType == int64(types.BURN_CLAIM_TYPE) {
oracleID = oracleID + "burn"
}
claimContent := NewOracleClaimContent(ethClaim.Chain33Receiver, ethClaim.Amount, ethClaim.ClaimType, ethClaim.Decimals)
claimBytes, err := json.Marshal(claimContent)
claimBytes, err := proto.Marshal(&claimContent)
if err != nil {
return types.OracleClaim{}, err
}
......@@ -69,34 +53,11 @@ func CreateOracleClaimFromEthClaim(ethClaim types.Eth2Chain33) (types.OracleClai
return claim, nil
}
// 通过oracleclaim反向构造ethchain33结构
func CreateEthClaimFromOracleString(ethereumChainID int64, bridgeContract string, nonce int64, localCoinSymbol, localCoinExec string, tokenContract string, ethereumAddress string, validator string, oracleClaimString string) (types.Eth2Chain33, error) {
oracleClaim, err := CreateOracleClaimFromOracleString(oracleClaimString)
if err != nil {
elog.Error("CreateEthClaimFromOracleString", "CreateOracleClaimFromOracleString error", err)
return types.Eth2Chain33{}, err
}
return NewEthBridgeClaim(
ethereumChainID,
bridgeContract,
nonce,
localCoinSymbol,
localCoinExec,
tokenContract,
ethereumAddress,
oracleClaim.Chain33Receiver,
validator,
oracleClaim.Amount,
oracleClaim.ClaimType,
), nil
}
func CreateOracleClaimFromOracleString(oracleClaimString string) (types.OracleClaimContent, error) {
var oracleClaimContent types.OracleClaimContent
bz := []byte(oracleClaimString)
if err := json.Unmarshal(bz, &oracleClaimContent); err != nil {
if err := proto.Unmarshal(bz, &oracleClaimContent); err != nil {
return types.OracleClaimContent{}, errors.New(fmt.Sprintf("failed to parse claim: %s", err.Error()))
}
......
package ethbridge
import (
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/executor/oracle"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
)
// OracleKeeper defines the expected oracle keeper
type OracleKeeper interface {
ProcessClaim(claim types.OracleClaim) (oracle.Status, error)
GetProphecy(id string) (oracle.Prophecy, error)
GetValidatorArray() ([]types.MsgValidator, error)
SetConsensusThreshold(ConsensusThreshold int64)
GetConsensusThreshold() int64
}
package ethbridge
import (
"encoding/json"
"github.com/golang/protobuf/proto"
"strconv"
"github.com/33cn/chain33/account"
......@@ -13,11 +13,11 @@ import (
)
type Keeper struct {
oracleKeeper OracleKeeper
oracleKeeper oracle.OracleKeeper
db dbm.KV
}
func NewKeeper(oracleKeeper OracleKeeper, db dbm.KV) Keeper {
func NewKeeper(oracleKeeper oracle.OracleKeeper, db dbm.KV) Keeper {
return Keeper{
oracleKeeper: oracleKeeper,
db: db,
......@@ -25,16 +25,16 @@ func NewKeeper(oracleKeeper OracleKeeper, db dbm.KV) Keeper {
}
// 处理接收到的ethchain33请求
func (k Keeper) ProcessClaim(claim types.Eth2Chain33) (oracle.Status, error) {
func (k Keeper) ProcessClaim(claim types.Eth2Chain33) (*types.ProphecyStatus, error) {
oracleClaim, err := CreateOracleClaimFromEthClaim(claim)
if err != nil {
elog.Error("CreateEthClaimFromOracleString", "CreateOracleClaimFromOracleString error", err)
return oracle.Status{}, err
return nil, err
}
status, err := k.oracleKeeper.ProcessClaim(oracleClaim)
if err != nil {
return oracle.Status{}, err
return nil, err
}
return status, nil
}
......@@ -52,14 +52,7 @@ func (k Keeper) ProcessSuccessfulClaimForLock(claim, execAddr, tokenSymbol, toke
if oracleClaim.ClaimType == int64(types.LOCK_CLAIM_TYPE) {
//铸币到相关的tokenSymbolBank账户下
d := oracleClaim.Decimals
var amount int64
if d > 8 {
amount = int64(types.Toeth(oracleClaim.Amount, d-8))
} else {
a, _ := strconv.ParseFloat(types.TrimZeroAndDot(oracleClaim.Amount), 64)
amount = int64(types.MultiplySpecifyTimes(a, 8-d))
}
amount, _ := strconv.ParseInt(types.TrimZeroAndDot(oracleClaim.Amount), 10, 64)
receipt, err = accDB.Mint(execAddr, amount)
if err != nil {
......@@ -103,12 +96,6 @@ func (k Keeper) ProcessSuccessfulClaimForBurn(claim, execAddr, tokenSymbol strin
// ProcessBurn processes the burn of bridged coins from the given sender
func (k Keeper) ProcessBurn(address, execAddr, amount, tokenAddress string, d int64, accDB *account.DB) (*types2.Receipt, error) {
var a int64
if d > 8 {
a = int64(types.Toeth(amount, d-8))
} else {
aa, _ := strconv.ParseFloat(types.TrimZeroAndDot(amount), 64)
a = int64(types.MultiplySpecifyTimes(aa, 8-d))
}
receipt, err := accDB.ExecWithdraw(execAddr, address, a)
if err != nil {
return nil, err
......@@ -135,7 +122,6 @@ func (k Keeper) ProcessLock(address, to, execAddr, amount string, accDB *account
return receipt, nil
}
//todo
// 对于相同的地址该如何处理?
// 现有方案是相同地址就报错
func (k Keeper) ProcessAddValidator(address string, power int64) (*types2.Receipt, error) {
......@@ -146,9 +132,13 @@ func (k Keeper) ProcessAddValidator(address string, power int64) (*types2.Receip
return nil, err
}
if validatorMaps == nil {
validatorMaps = new(types.ValidatorList)
}
elog.Info("ProcessLogInValidator", "pre validatorMaps", validatorMaps, "Add Address", address, "Add power", power)
var totalPower int64
for _, p := range validatorMaps {
for _, p := range validatorMaps.Validators {
if p.Address != address {
totalPower += p.Power
} else {
......@@ -156,18 +146,21 @@ func (k Keeper) ProcessAddValidator(address string, power int64) (*types2.Receip
}
}
validatorMaps = append(validatorMaps, types.MsgValidator{
vs := append(validatorMaps.Validators, &types.MsgValidator{
Address: address,
Power: power,
})
v, _ := json.Marshal(validatorMaps)
validatorMaps.Validators = vs
v, _ := proto.Marshal(validatorMaps)
receipt.KV = append(receipt.KV, &types2.KeyValue{Key: types.CalValidatorMapsPrefix(), Value: v})
totalPower += power
totalP := types.ReceiptQueryTotalPower{
TotalPower: totalPower,
}
totalPBytes, _ := json.Marshal(totalP)
totalPBytes, _ := proto.Marshal(&totalP)
receipt.KV = append(receipt.KV, &types2.KeyValue{Key: types.CalLastTotalPowerPrefix(), Value: totalPBytes})
return receipt, nil
}
......@@ -183,13 +176,13 @@ func (k Keeper) ProcessRemoveValidator(address string) (*types2.Receipt, error)
elog.Info("ProcessLogOutValidator", "pre validatorMaps", validatorMaps, "Delete Address", address)
var totalPower int64
var validatorRes []types.MsgValidator
for _, p := range validatorMaps {
validatorRes := new(types.ValidatorList)
for _, p := range validatorMaps.Validators {
if address != p.Address {
validatorRes = append(validatorRes, p)
v := append(validatorRes.Validators, p)
validatorRes.Validators = v
totalPower += p.Power
} else {
//oracle.RemoveAddrFromValidatorMap(validatorMaps, index)
exist = true
continue
}
......@@ -199,12 +192,12 @@ func (k Keeper) ProcessRemoveValidator(address string) (*types2.Receipt, error)
return nil, types.ErrAddressNotExist
}
v, _ := json.Marshal(validatorRes)
v, _ := proto.Marshal(validatorRes)
receipt.KV = append(receipt.KV, &types2.KeyValue{Key: types.CalValidatorMapsPrefix(), Value: v})
totalP := types.ReceiptQueryTotalPower{
TotalPower: totalPower,
}
totalPBytes, _ := json.Marshal(totalP)
totalPBytes, _ := proto.Marshal(&totalP)
receipt.KV = append(receipt.KV, &types2.KeyValue{Key: types.CalLastTotalPowerPrefix(), Value: totalPBytes})
return receipt, nil
}
......@@ -221,11 +214,11 @@ func (k Keeper) ProcessModifyValidator(address string, power int64) (*types2.Rec
elog.Info("ProcessModifyValidator", "pre validatorMaps", validatorMaps, "Modify Address", address, "Modify power", power)
var totalPower int64
for index, p := range validatorMaps {
for index, p := range validatorMaps.Validators {
if address != p.Address {
totalPower += p.Power
} else {
validatorMaps[index].Power = power
validatorMaps.Validators[index].Power = power
exist = true
totalPower += power
}
......@@ -235,18 +228,18 @@ func (k Keeper) ProcessModifyValidator(address string, power int64) (*types2.Rec
return nil, types.ErrAddressNotExist
}
v, _ := json.Marshal(validatorMaps)
v, _ := proto.Marshal(validatorMaps)
receipt.KV = append(receipt.KV, &types2.KeyValue{Key: types.CalValidatorMapsPrefix(), Value: v})
totalP := types.ReceiptQueryTotalPower{
TotalPower: totalPower,
}
totalPBytes, _ := json.Marshal(totalP)
totalPBytes, _ := proto.Marshal(&totalP)
receipt.KV = append(receipt.KV, &types2.KeyValue{Key: types.CalLastTotalPowerPrefix(), Value: totalPBytes})
return receipt, nil
}
func (k Keeper) ProcessSetConsensusNeeded(ConsensusThreshold int64) (int64, int64, error) {
func (k *Keeper) ProcessSetConsensusNeeded(ConsensusThreshold int64) (int64, int64, error) {
preCon := k.oracleKeeper.GetConsensusThreshold()
k.oracleKeeper.SetConsensusThreshold(ConsensusThreshold)
nowCon := k.oracleKeeper.GetConsensusThreshold()
......
package ethbridge
import (
"strconv"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/executor/common"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
gethCommon "github.com/ethereum/go-ethereum/common"
)
type Msg_Burn struct {
EthereumChainID int64 `json:"ethereum_chain_id" yaml:"ethereum_chain_id"`
TokenContract common.EthAddress `json:"token_contract_address" yaml:"token_contract_address"`
Chain33Sender string `json:"chain33_sender" yaml:"chain33_sender"`
EthereumReceiver common.EthAddress `json:"ethereum_receiver" yaml:"ethereum_receiver"`
Amount uint64 `json:"amount" yaml:"amount"`
}
func NewMsgBurn(ethereumChainID int64, tokenContract string, chain33Sender string, ethereumReceiver string, amount uint64) Msg_Burn {
return Msg_Burn{
EthereumChainID: ethereumChainID,
TokenContract: common.NewEthereumAddress(tokenContract),
Chain33Sender: chain33Sender,
EthereumReceiver: common.NewEthereumAddress(ethereumReceiver),
Amount: amount,
}
}
// Route should return the name of the module
func (msg Msg_Burn) Route() string { return types.ModuleName }
// Type should return the action
func (msg Msg_Burn) Type() string { return "burn" }
// ValidateBasic runs stateless checks on the message
func (msg Msg_Burn) ValidateBasic() error {
if strconv.Itoa(int(msg.EthereumChainID)) == "" {
return types.ErrInvalidChainID
}
if msg.TokenContract.String() == "" {
return types.ErrInvalidEthAddress
}
if !gethCommon.IsHexAddress(msg.TokenContract.String()) {
return types.ErrInvalidEthAddress
}
if types.AddressIsEmpty(msg.Chain33Sender) {
return types.ErrInvalidAddress
}
if msg.EthereumReceiver.String() == "" {
return types.ErrInvalidEthAddress
}
if !gethCommon.IsHexAddress(msg.EthereumReceiver.String()) {
return types.ErrInvalidEthAddress
}
return nil
}
package ethbridge
import (
"errors"
"fmt"
"strings"
"github.com/33cn/chain33/common/address"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
gethCommon "github.com/ethereum/go-ethereum/common"
)
// MsgCreateEthBridgeClaim defines a message for creating claims on the ethereum bridge
type MsgCreateEthBridgeClaim types.Eth2Chain33
// NewMsgCreateEthBridgeClaim is a constructor function for MsgCreateBridgeClaim
func NewMsgCreateEthBridgeClaim(ethBridgeClaim types.Eth2Chain33) MsgCreateEthBridgeClaim {
return MsgCreateEthBridgeClaim(ethBridgeClaim)
}
// Route should return the name of the module
func (msg MsgCreateEthBridgeClaim) Route() string { return types.ModuleName }
// Type should return the action
func (msg MsgCreateEthBridgeClaim) Type() string { return "create_bridge_claim" }
// ValidateBasic runs stateless checks on the message
func (msg MsgCreateEthBridgeClaim) ValidateBasic() error {
if types.AddressIsEmpty(msg.Chain33Receiver) {
return types.ErrInvalidAddress
}
if types.AddressIsEmpty(msg.ValidatorAddress) {
return types.ErrInvalidAddress
}
if msg.Nonce < 0 {
return types.ErrInvalidEthNonce
}
if !gethCommon.IsHexAddress(msg.EthereumSender) {
return types.ErrInvalidEthAddress
}
if !gethCommon.IsHexAddress(msg.BridgeContractAddress) {
return types.ErrInvalidEthAddress
}
if strings.ToLower(msg.LocalCoinSymbol) == "eth" && msg.TokenContractAddress != "0x0000000000000000000000000000000000000000" {
return types.ErrInvalidEthSymbol
}
return nil
}
// MapOracleClaimsToEthBridgeClaims maps a set of generic oracle claim data into EthBridgeClaim objects
func MapOracleClaimsToEthBridgeClaims(ethereumChainID int, bridgeContract string, nonce int, symbol string, tokenContract string, ethereumSender string, oracleValidatorClaims map[string]string, f func(int, string, int, string, string, string, string, string) (types.Eth2Chain33, error)) ([]types.Eth2Chain33, error) {
mappedClaims := make([]types.Eth2Chain33, len(oracleValidatorClaims))
i := 0
for validator, validatorClaim := range oracleValidatorClaims {
parseErr := address.CheckAddress(validator)
if parseErr != nil {
return nil, errors.New(fmt.Sprintf("failed to parse claim: %s", parseErr))
}
mappedClaim, err := f(ethereumChainID, bridgeContract, nonce, symbol, tokenContract, ethereumSender, validator, validatorClaim)
if err != nil {
return nil, err
}
mappedClaims[i] = mappedClaim
i++
}
return mappedClaims, nil
}
package ethbridge
import (
"strconv"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/executor/common"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
gethCommon "github.com/ethereum/go-ethereum/common"
)
// MsgLock defines a message for locking coins and triggering a related event
type MsgLock struct {
EthereumChainID int `json:"ethereum_chain_id" yaml:"ethereum_chain_id"`
TokenContract common.EthAddress `json:"token_contract_address" yaml:"token_contract_address"`
Chain33Sender string `json:"chain33_sender" yaml:"chain33_sender"`
EthereumReceiver common.EthAddress `json:"ethereum_receiver" yaml:"ethereum_receiver"`
Amount uint64 `json:"amount" yaml:"amount"`
}
// NewMsgLock is a constructor function for MsgLock
func NewMsgLock(ethereumChainID int, tokenContract string, cosmosSender string, ethereumReceiver string, amount uint64) MsgLock {
return MsgLock{
EthereumChainID: ethereumChainID,
TokenContract: common.NewEthereumAddress(tokenContract),
Chain33Sender: cosmosSender,
EthereumReceiver: common.NewEthereumAddress(ethereumReceiver),
Amount: amount,
}
}
// Route should return the name of the module
func (msg MsgLock) Route() string { return types.ModuleName }
// Type should return the action
func (msg MsgLock) Type() string { return "lock" }
// ValidateBasic runs stateless checks on the message
func (msg MsgLock) ValidateBasic() error {
if strconv.Itoa(msg.EthereumChainID) == "" {
return types.ErrInvalidChainID
}
if msg.TokenContract.String() == "" {
return types.ErrInvalidEthAddress
}
if !gethCommon.IsHexAddress(msg.TokenContract.String()) {
return types.ErrInvalidEthAddress
}
if types.AddressIsEmpty(msg.Chain33Sender) {
return types.ErrInvalidAddress
}
if msg.EthereumReceiver.String() == "" {
return types.ErrInvalidEthAddress
}
if !gethCommon.IsHexAddress(msg.EthereumReceiver.String()) {
return types.ErrInvalidEthAddress
}
return nil
}
......@@ -19,57 +19,56 @@ import (
// 然后relayer端订阅到该消息后向chain33发送该类型消息
// 本端在验证该类型的请求合理后铸币,并生成相同数额的token
func (x *x2ethereum) Exec_Eth2Chain33(payload *x2ethereumtypes.Eth2Chain33, tx *types.Transaction, index int) (*types.Receipt, error) {
action, defaultCon := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
if payload.ValidatorAddress == "" {
payload.ValidatorAddress = address.PubKeyToAddr(tx.Signature.Pubkey)
}
return action.procMsgEth2Chain33(payload, defaultCon)
payload.ValidatorAddress = address.PubKeyToAddr(tx.Signature.Pubkey)
return action.procMsgEth2Chain33(payload)
}
// 将因ethereum端锁定的eth或者erc20而在chain33端生成的token返还
func (x *x2ethereum) Exec_WithdrawEth(payload *x2ethereumtypes.Eth2Chain33, tx *types.Transaction, index int) (*types.Receipt, error) {
action, defaultCon := newAction(x, tx, int32(index))
// WithdrawChain33类型的交易是将Eth端因Chain33端锁定所生成的token返还给Chain33端(Burn)
func (x *x2ethereum) Exec_WithdrawChain33(payload *x2ethereumtypes.Chain33ToEth, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
if payload.ValidatorAddress == "" {
payload.ValidatorAddress = address.PubKeyToAddr(tx.Signature.Pubkey)
}
return action.procWithdrawEth(payload, defaultCon)
return action.procMsgBurn(payload)
}
//---------------- Chain33(eth/erc20) --> Ethereum-------------------//
// WithdrawChain33类型的交易是Chain33侧将本端生成的token返还到Ethereum端
func (x *x2ethereum) Exec_WithdrawChain33(payload *x2ethereumtypes.Chain33ToEth, tx *types.Transaction, index int) (*types.Receipt, error) {
action, defaultCon := newAction(x, tx, int32(index))
// 将因ethereum端锁定的eth或者erc20而在chain33端生成的token返还
func (x *x2ethereum) Exec_WithdrawEth(payload *x2ethereumtypes.Eth2Chain33, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
return action.procMsgBurn(payload, defaultCon)
payload.ValidatorAddress = address.PubKeyToAddr(tx.Signature.Pubkey)
return action.procWithdrawEth(payload)
}
// Chain33ToEth类型的交易是Chain33侧在本端发出申请
// 在本端锁定一定数额的token,然后在ethereum端生成相同数额的token
func (x *x2ethereum) Exec_Chain33ToEth(payload *x2ethereumtypes.Chain33ToEth, tx *types.Transaction, index int) (*types.Receipt, error) {
action, defaultCon := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
return action.procMsgLock(payload, defaultCon)
return action.procMsgLock(payload)
}
// 转账功能
func (x *x2ethereum) Exec_Transfer(payload *types.AssetsTransfer, tx *types.Transaction, index int) (*types.Receipt, error) {
action, defaultCon := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
return action.procMsgTransfer(payload, defaultCon)
return action.procMsgTransfer(payload)
}
//--------------------------合约管理员账户操作-------------------------//
......@@ -78,11 +77,11 @@ func (x *x2ethereum) Exec_Transfer(payload *types.AssetsTransfer, tx *types.Tran
func (x *x2ethereum) Exec_AddValidator(payload *x2ethereumtypes.MsgValidator, tx *types.Transaction, index int) (*types.Receipt, error) {
err := checkTxSignBySpecificAddr(tx, x2ethereumtypes.X2ethereumAdmin)
if err == nil {
action, defaultCon := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
return action.procAddValidator(payload, defaultCon)
return action.procAddValidator(payload)
}
return nil, err
}
......@@ -91,11 +90,11 @@ func (x *x2ethereum) Exec_AddValidator(payload *x2ethereumtypes.MsgValidator, tx
func (x *x2ethereum) Exec_RemoveValidator(payload *x2ethereumtypes.MsgValidator, tx *types.Transaction, index int) (*types.Receipt, error) {
err := checkTxSignBySpecificAddr(tx, x2ethereumtypes.X2ethereumAdmin)
if err == nil {
action, defaultCon := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
return action.procRemoveValidator(payload, defaultCon)
return action.procRemoveValidator(payload)
}
return nil, err
}
......@@ -104,11 +103,11 @@ func (x *x2ethereum) Exec_RemoveValidator(payload *x2ethereumtypes.MsgValidator,
func (x *x2ethereum) Exec_ModifyPower(payload *x2ethereumtypes.MsgValidator, tx *types.Transaction, index int) (*types.Receipt, error) {
err := checkTxSignBySpecificAddr(tx, x2ethereumtypes.X2ethereumAdmin)
if err == nil {
action, defaultCon := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
return action.procModifyValidator(payload, defaultCon)
return action.procModifyValidator(payload)
}
return nil, err
}
......@@ -117,7 +116,7 @@ func (x *x2ethereum) Exec_ModifyPower(payload *x2ethereumtypes.MsgValidator, tx
func (x *x2ethereum) Exec_SetConsensusThreshold(payload *x2ethereumtypes.MsgConsensusThreshold, tx *types.Transaction, index int) (*types.Receipt, error) {
err := checkTxSignBySpecificAddr(tx, x2ethereumtypes.X2ethereumAdmin)
if err == nil {
action, _ := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
......
package oracle
import (
"encoding/json"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
)
type Prophecy struct {
ID string `json:"id"`
Status Status `json:"status"`
ClaimValidators []*types.ClaimValidators `json:"claim_validators"`
ValidatorClaims []*types.ValidatorClaims `json:"validator_claims"`
}
func NewProphecy(id string) *types.ReceiptEthProphecy {
func NewProphecy(id string) Prophecy {
return Prophecy{
status := new(types.ProphecyStatus)
status.Text = types.EthBridgeStatus_PendingStatusText
return &types.ReceiptEthProphecy{
ID: id,
Status: NewStatus(StatusText(types.EthBridgeStatus_PendingStatusText), ""),
Status: status,
ClaimValidators: *new([]*types.ClaimValidators),
ValidatorClaims: *new([]*types.ValidatorClaims),
}
}
func NewEmptyProphecy() Prophecy {
func NewEmptyProphecy() *types.ReceiptEthProphecy {
return NewProphecy("")
}
type DBProphecy struct {
ID string `json:"id"`
Status Status `json:"status"`
ClaimValidators []byte `json:"claim_validators"`
ValidatorClaims []byte `json:"validator_claims"`
}
// SerializeForDB serializes a prophecy into a DBProphecy
func (prophecy Prophecy) SerializeForDB() (DBProphecy, error) {
claimValidators, err := json.Marshal(prophecy.ClaimValidators)
if err != nil {
return DBProphecy{}, err
}
validatorClaims, err := json.Marshal(prophecy.ValidatorClaims)
if err != nil {
return DBProphecy{}, err
}
return DBProphecy{
ID: prophecy.ID,
Status: prophecy.Status,
ClaimValidators: claimValidators,
ValidatorClaims: validatorClaims,
}, nil
}
// DeserializeFromDB deserializes a DBProphecy into a prophecy
func (dbProphecy DBProphecy) DeserializeFromDB() (Prophecy, error) {
claimValidators := new([]*types.ClaimValidators)
err := json.Unmarshal(dbProphecy.ClaimValidators, &claimValidators)
if err != nil {
return Prophecy{}, err
}
validatorClaims := new([]*types.ValidatorClaims)
err = json.Unmarshal(dbProphecy.ValidatorClaims, &validatorClaims)
if err != nil {
return Prophecy{}, err
}
return Prophecy{
ID: dbProphecy.ID,
Status: dbProphecy.Status,
ClaimValidators: *claimValidators,
ValidatorClaims: *validatorClaims,
}, nil
}
//
//type DBProphecy struct {
// ID string `json:"id"`
// Status Status `json:"status"`
// ClaimValidators []byte `json:"claim_validators"`
// ValidatorClaims []byte `json:"validator_claims"`
//}
//
//// SerializeForDB serializes a prophecy into a DBProphecy
//func (prophecy Prophecy) SerializeForDB() (DBProphecy, error) {
// claimValidators, err := json.Marshal(prophecy.ClaimValidators)
// if err != nil {
// return DBProphecy{}, err
// }
//
// validatorClaims, err := json.Marshal(prophecy.ValidatorClaims)
// if err != nil {
// return DBProphecy{}, err
// }
//
// return DBProphecy{
// ID: prophecy.ID,
// Status: prophecy.Status,
// ClaimValidators: claimValidators,
// ValidatorClaims: validatorClaims,
// }, nil
//}
//
//// DeserializeFromDB deserializes a DBProphecy into a prophecy
//func (dbProphecy DBProphecy) DeserializeFromDB() (Prophecy, error) {
// claimValidators := new([]*types.ClaimValidators)
// err := json.Unmarshal(dbProphecy.ClaimValidators, &claimValidators)
// if err != nil {
// return Prophecy{}, err
// }
//
// validatorClaims := new([]*types.ValidatorClaims)
// err = json.Unmarshal(dbProphecy.ValidatorClaims, &validatorClaims)
// if err != nil {
// return Prophecy{}, err
// }
//
// return Prophecy{
// ID: dbProphecy.ID,
// Status: dbProphecy.Status,
// ClaimValidators: *claimValidators,
// ValidatorClaims: *validatorClaims,
// }, nil
//}
// AddClaim adds a given claim to this prophecy
func (prophecy *Prophecy) AddClaim(validator string, claim string) {
func AddClaim(prophecy *types.ReceiptEthProphecy, validator string, claim string) {
claimValidators := new(types.StringMap)
if len(prophecy.ClaimValidators) == 0 {
prophecy.ClaimValidators = append(prophecy.ClaimValidators, &types.ClaimValidators{
......@@ -95,29 +91,36 @@ func (prophecy *Prophecy) AddClaim(validator string, claim string) {
}
}
if len(prophecy.ValidatorClaims) == 0 {
prophecy.ValidatorClaims = append(prophecy.ValidatorClaims, &types.ValidatorClaims{
Validator: validator,
Claim: claim,
})
} else {
for index, vc := range prophecy.ValidatorClaims {
if vc.Validator == validator {
prophecy.ValidatorClaims[index].Claim = claim
break
} else {
prophecy.ValidatorClaims = append(prophecy.ValidatorClaims, &types.ValidatorClaims{
Validator: validator,
Claim: claim,
})
}
}
}
//todo
// validator不可能相同?
//if len(prophecy.ValidatorClaims) == 0 {
// prophecy.ValidatorClaims = append(prophecy.ValidatorClaims, &types.ValidatorClaims{
// Validator: validator,
// Claim: claim,
// })
//} else {
// for index, vc := range prophecy.ValidatorClaims {
// if vc.Validator == validator {
// prophecy.ValidatorClaims[index].Claim = claim
// break
// } else {
// prophecy.ValidatorClaims = append(prophecy.ValidatorClaims, &types.ValidatorClaims{
// Validator: validator,
// Claim: claim,
// })
// }
// }
//}
prophecy.ValidatorClaims = append(prophecy.ValidatorClaims, &types.ValidatorClaims{
Validator: validator,
Claim: claim,
})
}
// 遍历该prophecy所有claim,找出获得最多票数的claim
func (prophecy *Prophecy) FindHighestClaim(validators map[string]int64) (string, int64, int64) {
func FindHighestClaim(prophecy *types.ReceiptEthProphecy, validators map[string]int64) (string, int64, int64) {
totalClaimsPower := int64(0)
highestClaimPower := int64(-1)
highestClaim := ""
......@@ -135,17 +138,3 @@ func (prophecy *Prophecy) FindHighestClaim(validators map[string]int64) (string,
}
return highestClaim, highestClaimPower, totalClaimsPower
}
// Status is a struct that contains the status of a given prophecy
type Status struct {
Text StatusText `json:"text"`
FinalClaim string `json:"final_claim"`
}
// NewStatus returns a new Status with the given data contained
func NewStatus(text StatusText, finalClaim string) Status {
return Status{
Text: text,
FinalClaim: finalClaim,
}
}
package oracle
import (
"encoding/json"
"fmt"
"strconv"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
)
// StatusText is an enum used to represent the status of the prophecy
type StatusText int
var StatusTextToString = [...]string{"pending", "success", "failed", "withdrawed"}
var StringToStatusText = map[string]types.EthBridgeStatus{
"pending": types.EthBridgeStatus_PendingStatusText,
"success": types.EthBridgeStatus_SuccessStatusText,
"failed": types.EthBridgeStatus_FailedStatusText,
"withdrawed": types.EthBridgeStatus_WithdrawedStatusText,
}
func (text StatusText) String() string {
return StatusTextToString[text]
}
func (text StatusText) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%v\"", text.String())), nil
}
func (text *StatusText) UnmarshalJSON(b []byte) error {
var j string
err := json.Unmarshal(b, &j)
if err != nil {
return err
}
stringKey, err := strconv.Unquote(string(b))
if err != nil {
return err
}
// Note that if the string cannot be found then it will be set to the zero value, 'pending' in this case.
*text = StatusText(StringToStatusText[stringKey])
return nil
}
package executor
import (
"encoding/json"
"github.com/golang/protobuf/proto"
"strconv"
"strings"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/executor/oracle"
types2 "github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
)
func (x *x2ethereum) Query_GetEthProphecy(in *types2.QueryEthProphecyParams) (types.Message, error) {
prophecy := &types2.ReceiptEthProphecy{}
prophecyKey := types2.CalProphecyPrefix()
prophecyKey := types2.CalProphecyPrefix(in.ID)
var dbProphecy types2.ReceiptEthProphecy
var dbProphecy []oracle.DBProphecy
val, err := x.GetStateDB().Get(prophecyKey)
if err != nil {
return nil, err
}
err = json.Unmarshal(val, &dbProphecy)
err = proto.Unmarshal(val, &dbProphecy)
if err != nil {
return nil, types.ErrUnmarshal
}
for _, dbP := range dbProphecy {
if dbP.ID == in.ID {
dbPD, err := dbP.DeserializeFromDB()
if err != nil {
return nil, err
}
prophecy = &types2.ReceiptEthProphecy{
ID: in.ID,
Status: &types2.ProphecyStatus{
Text: types2.EthBridgeStatus(dbP.Status.Text),
FinalClaim: dbP.Status.FinalClaim,
},
ClaimValidators: dbPD.ClaimValidators,
ValidatorClaims: dbPD.ValidatorClaims,
}
return prophecy, nil
}
}
return nil, types2.ErrInvalidProphecyID
return &dbProphecy, nil
}
func (x *x2ethereum) Query_GetValidators(in *types2.QueryValidatorsParams) (types.Message, error) {
validatorsKey := types2.CalValidatorMapsPrefix()
var v []*types2.MsgValidator
var v types2.ValidatorList
vBytes, err := x.GetStateDB().Get(validatorsKey)
if err != nil {
elog.Error("Query_GetValidators", "GetValidators Err", err)
return nil, err
}
err = json.Unmarshal(vBytes, &v)
err = proto.Unmarshal(vBytes, &v)
if err != nil {
return nil, types.ErrUnmarshal
}
if in.Validator != "" {
validatorsRes := new(types2.ReceiptQueryValidator)
for _, vv := range v {
for _, vv := range v.Validators {
if vv.Address == in.Validator {
val := make([]*types2.MsgValidator, 1)
val[0] = vv
......@@ -81,10 +62,10 @@ func (x *x2ethereum) Query_GetValidators(in *types2.QueryValidatorsParams) (type
} else {
validatorsRes := new(types2.ReceiptQueryValidator)
var totalPower int64
for _, vv := range v {
for _, vv := range v.Validators {
totalPower += vv.Power
}
validatorsRes.Validators = v
validatorsRes.Validators = v.Validators
validatorsRes.TotalPower = totalPower
return validatorsRes, nil
}
......@@ -99,7 +80,7 @@ func (x *x2ethereum) Query_GetTotalPower(in *types2.QueryTotalPowerParams) (type
elog.Error("Query_GetTotalPower", "GetTotalPower Err", err)
return nil, err
}
err = json.Unmarshal(totalPowerBytes, &totalPower)
err = proto.Unmarshal(totalPowerBytes, totalPower)
if err != nil {
return nil, types.ErrUnmarshal
}
......@@ -107,7 +88,7 @@ func (x *x2ethereum) Query_GetTotalPower(in *types2.QueryTotalPowerParams) (type
}
func (x *x2ethereum) Query_GetConsensusThreshold(in *types2.QueryConsensusThresholdParams) (types.Message, error) {
consensus := &types2.ReceiptSetConsensusThreshold{}
consensus := &types2.ReceiptQueryConsensusThreshold{}
consensusKey := types2.CalConsensusThresholdPrefix()
consensusBytes, err := x.GetStateDB().Get(consensusKey)
......@@ -115,7 +96,7 @@ func (x *x2ethereum) Query_GetConsensusThreshold(in *types2.QueryConsensusThresh
elog.Error("Query_GetConsensusNeeded", "GetConsensusNeeded Err", err)
return nil, err
}
err = json.Unmarshal(consensusBytes, &consensus)
err = proto.Unmarshal(consensusBytes, consensus)
if err != nil {
return nil, types.ErrUnmarshal
}
......
......@@ -53,7 +53,11 @@ func (x *x2ethereum) GetDriverName() string {
}
// CheckTx 实现自定义检验交易接口,供框架调用
// todo
// 实现
func (x *x2ethereum) CheckTx(tx *types.Transaction, index int) error {
// implement code
//var action x2ethereumtypes.X2EthereumAction
//err := types.Decode(tx.Payload, &action)
//if action.Ty
return nil
}
......@@ -8,7 +8,6 @@ enum EthBridgeStatus {
PendingStatusText = 0;
SuccessStatusText = 1;
FailedStatusText = 2;
WithdrawedStatusText = 3;
}
message X2ethereumAction {
......@@ -138,6 +137,10 @@ message StringMap {
repeated string validators = 1;
}
message ValidatorList {
repeated MsgValidator validators = 1;
}
message ProphecyStatus {
EthBridgeStatus Text = 1;
string FinalClaim = 2;
......
# 测试流程
1. 起eth节点
```
cd /opt/src/github.com/cosmos/peggy/testnet-contracts
truffle develop
```
2. 起chain33节点
```
make docker-compose
```
3. 修改配置项,起relayer
修改 chain33Host,BridgeRegistry,pushHost,operatorAddr,deployerPrivateKey,validatorsAddr
注意:
BridgeRegistry 需要先起relayer然后部署完成后才有,然后停掉relayer,重新跑
4. 修改脚本中的私钥,跑部署脚本
```
./bridgeBankTest.sh
```
5. 在ethereum上发行bty
```
./ebcli_A relayer ethereum token4chain33 -s bty
```
6. 跑测试用例
```
./test.sh
```
7. 查询ispending的prophecy
```
./ebcli_A relayer ethereum ispending -i 1
```
8. 处理这个prophecy
```
./ebcli_A relayer ethereum process -i 1
```
9. 查询余额
```
./ebcli_A relayer ethereum balance -o 0x7B95B6EC7EbD73572298cEf32Bb54FA408207359 -a 0xbAf2646b8DaD8776fc74Bf4C8d59E6fB3720eddf
```
......@@ -27,6 +27,7 @@ var (
ErrAddressExists = errors.New("This address already exists")
ErrInvalidAdminAddress = errors.New("This address is not admin address")
ErrClaimInconsist = errors.New("This claim does not consist with others")
ErrInvalidPower = errors.New("This power is invalid")
)
//common
......
......@@ -15,8 +15,8 @@ var (
KeyPrefixLocalDB = "LODB-x2ethereum-"
)
func CalProphecyPrefix() []byte {
return []byte(KeyPrefixStateDB + string(ProphecyKey))
func CalProphecyPrefix(id string) []byte {
return []byte(KeyPrefixStateDB + string(ProphecyKey) + id)
}
func CalEth2Chain33Prefix() []byte {
......
......@@ -5,9 +5,8 @@ package types
import (
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
......
......@@ -95,3 +95,10 @@ func TrimZeroAndDot(s string) string {
return s
}
func CheckPower(power int64) bool {
if power <= 0 || power > 100 {
return false
}
return true
}
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