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)
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/golang/protobuf/proto"
"strings"
dbm "github.com/33cn/chain33/common/db"
......@@ -15,154 +15,77 @@ var (
olog = log.New("module", "oracle")
)
type Keeper struct {
type OracleKeeper struct {
db dbm.KV
// 通过审核的最低阈值
ConsensusThreshold int64
}
func NewKeeper(db dbm.KV, ConsensusThreshold int64) *Keeper {
func NewOracleKeeper(db dbm.KV, ConsensusThreshold int64) *OracleKeeper {
if ConsensusThreshold <= 0 || ConsensusThreshold > 100 {
return nil
}
return &Keeper{
return &OracleKeeper{
db: db,
ConsensusThreshold: ConsensusThreshold,
}
}
func (k *Keeper) GetProphecy(id string) (Prophecy, error) {
func (k *OracleKeeper) GetProphecy(id string) (*types.ReceiptEthProphecy, error) {
if id == "" {
return NewEmptyProphecy(), types.ErrInvalidIdentifier
}
bz, err := k.db.Get(types.CalProphecyPrefix())
bz, err := k.db.Get(types.CalProphecyPrefix(id))
if err != nil && err != types2.ErrNotFound {
return NewEmptyProphecy(), types.ErrProphecyGet
} else if err == types2.ErrNotFound {
return NewEmptyProphecy(), types.ErrProphecyNotFound
}
var dbProphecys []DBProphecy
var dbProphecy DBProphecy
err = json.Unmarshal(bz, &dbProphecys)
if err != nil {
return NewEmptyProphecy(), types2.ErrUnmarshal
}
var exist bool
for _, p := range dbProphecys {
if p.ID == id {
dbProphecy = p
exist = true
break
}
}
if exist {
deSerializedProphecy, err := dbProphecy.DeserializeFromDB()
var dbProphecy types.ReceiptEthProphecy
err = proto.Unmarshal(bz, &dbProphecy)
if err != nil {
return NewEmptyProphecy(), types.ErrinternalDB
}
return deSerializedProphecy, nil
} else {
return NewEmptyProphecy(), types.ErrProphecyNotFound
return NewEmptyProphecy(), types2.ErrUnmarshal
}
return &dbProphecy, nil
}
// setProphecy saves a prophecy with an initial claim
func (k *Keeper) setProphecy(prophecy Prophecy) error {
func (k *OracleKeeper) setProphecy(prophecy *types.ReceiptEthProphecy) error {
err := k.checkProphecy(prophecy)
if err != nil {
return err
}
serializedProphecy, err := prophecy.SerializeForDB()
if err != nil {
return types.ErrinternalDB
}
bz, err := k.db.Get(types.CalProphecyPrefix())
bz, err := k.db.Get(types.CalProphecyPrefix(prophecy.ID))
if err != nil && err != types2.ErrNotFound {
return types.ErrProphecyGet
}
var dbProphecys []DBProphecy
var dbProphecy types.ReceiptEthProphecy
if err != types2.ErrNotFound {
err = json.Unmarshal(bz, &dbProphecys)
err = proto.Unmarshal(bz, &dbProphecy)
if err != nil {
return types2.ErrUnmarshal
}
}
var exist bool
for index, dbP := range dbProphecys {
if dbP.ID == serializedProphecy.ID {
exist = true
dbProphecys[index] = serializedProphecy
break
}
}
if !exist {
dbProphecys = append(dbProphecys, serializedProphecy)
}
dbProphecy = *prophecy
serializedProphecyBytes, err := json.Marshal(dbProphecys)
serializedProphecyBytes, err := proto.Marshal(&dbProphecy)
if err != nil {
return types2.ErrMarshal
}
err = k.db.Set(types.CalProphecyPrefix(), serializedProphecyBytes)
err = k.db.Set(types.CalProphecyPrefix(prophecy.ID), serializedProphecyBytes)
if err != nil {
return types.ErrSetKV
}
return nil
}
// modifyProphecy saves a modified prophecy
func (k *Keeper) modifyProphecy(prophecy Prophecy) error {
err := k.checkProphecy(prophecy)
if err != nil {
return err
}
serializedProphecy, err := prophecy.SerializeForDB()
if err != nil {
return types.ErrinternalDB
}
bz, err := k.db.Get(types.CalProphecyPrefix())
if err != nil && err != types2.ErrNotFound {
return types.ErrProphecyGet
}
var dbProphecys []DBProphecy
if err != types2.ErrNotFound {
err = json.Unmarshal(bz, &dbProphecys)
if err != nil {
return types2.ErrUnmarshal
}
}
for index, dbP := range dbProphecys {
if dbP.ID == serializedProphecy.ID {
dbProphecys[index] = serializedProphecy
break
}
}
serializedProphecyBytes, err := json.Marshal(dbProphecys)
if err != nil {
return types2.ErrMarshal
}
err = k.db.Set(types.CalProphecyPrefix(), serializedProphecyBytes)
if err != nil {
return types.ErrSetKV
}
return nil
}
func (k *Keeper) checkProphecy(prophecy Prophecy) error {
func (k *OracleKeeper) checkProphecy(prophecy *types.ReceiptEthProphecy) error {
if prophecy.ID == "" {
return types.ErrInvalidIdentifier
}
......@@ -172,23 +95,23 @@ func (k *Keeper) checkProphecy(prophecy Prophecy) error {
return nil
}
func (k *Keeper) ProcessClaim(claim types.OracleClaim) (Status, error) {
func (k *OracleKeeper) ProcessClaim(claim types.OracleClaim) (*types.ProphecyStatus, error) {
activeValidator := k.checkActiveValidator(claim.ValidatorAddress)
if !activeValidator {
return Status{}, types.ErrInvalidValidator
return nil, types.ErrInvalidValidator
}
if strings.TrimSpace(claim.Content) == "" {
return Status{}, types.ErrInvalidClaim
return nil, types.ErrInvalidClaim
}
var claimContent types.OracleClaimContent
err := json.Unmarshal([]byte(claim.Content), &claimContent)
err := proto.Unmarshal([]byte(claim.Content), &claimContent)
if err != nil {
return Status{}, types2.ErrUnmarshal
return nil, types2.ErrUnmarshal
}
prophecy, err := k.GetProphecy(claim.ID)
if err != nil {
if err != types.ErrProphecyNotFound {
return Status{}, err
return nil, err
}
prophecy = NewProphecy(claim.ID)
} else {
......@@ -199,40 +122,37 @@ func (k *Keeper) ProcessClaim(claim types.OracleClaim) (Status, error) {
}
}
if !exist {
prophecy.Status.Text = StatusText(types.EthBridgeStatus_FailedStatusText)
return Status{}, types.ErrClaimInconsist
prophecy.Status.Text = types.EthBridgeStatus_FailedStatusText
return nil, types.ErrClaimInconsist
}
if claimContent.ClaimType == int64(types.LOCK_CLAIM_TYPE) {
if prophecy.Status.Text == StatusText(types.EthBridgeStatus_SuccessStatusText) || prophecy.Status.Text == StatusText(types.EthBridgeStatus_FailedStatusText) {
return Status{}, types.ErrProphecyFinalized
if prophecy.Status.Text == types.EthBridgeStatus_FailedStatusText {
return nil, types.ErrProphecyFinalized
}
for _, vc := range prophecy.ValidatorClaims {
if vc.Validator == claim.ValidatorAddress && vc.Claim != "" {
return Status{}, types.ErrDuplicateMessage
return nil, types.ErrDuplicateMessage
}
}
} else if claimContent.ClaimType == int64(types.BURN_CLAIM_TYPE) {
if prophecy.Status.Text == StatusText(types.EthBridgeStatus_WithdrawedStatusText) || prophecy.Status.Text == StatusText(types.EthBridgeStatus_FailedStatusText) {
return Status{}, types.ErrProphecyFinalized
}
}
AddClaim(prophecy, claim.ValidatorAddress, claim.Content)
prophecy, err = k.processCompletion(prophecy, claimContent.ClaimType)
if err != nil {
return nil, err
}
prophecy.AddClaim(claim.ValidatorAddress, claim.Content)
prophecy, err = k.processCompletion(&prophecy, claimContent.ClaimType)
err = k.setProphecy(prophecy)
if err != nil {
return Status{}, err
return nil, err
}
return prophecy.Status, nil
}
func (k *Keeper) checkActiveValidator(validatorAddress string) bool {
func (k *OracleKeeper) checkActiveValidator(validatorAddress string) bool {
validatorMap, err := k.GetValidatorArray()
if err != nil {
return false
}
for _, v := range validatorMap {
for _, v := range validatorMap.Validators {
if v.Address == validatorAddress {
return true
}
......@@ -241,41 +161,37 @@ func (k *Keeper) checkActiveValidator(validatorAddress string) bool {
}
// 计算该prophecy是否达标
func (k *Keeper) processCompletion(prophecy *Prophecy, claimType int64) (Prophecy, error) {
func (k *OracleKeeper) processCompletion(prophecy *types.ReceiptEthProphecy, claimType int64) (*types.ReceiptEthProphecy, error) {
address2power := make(map[string]int64)
validatorArrays, err := k.GetValidatorArray()
if err != nil {
return *prophecy, err
return nil, err
}
for _, validator := range validatorArrays {
for _, validator := range validatorArrays.Validators {
address2power[validator.Address] = validator.Power
}
highestClaim, highestClaimPower, totalClaimsPower := prophecy.FindHighestClaim(address2power)
highestClaim, highestClaimPower, totalClaimsPower := FindHighestClaim(prophecy, address2power)
totalPower, err := k.GetLastTotalPower()
if err != nil {
return *prophecy, err
return nil, err
}
highestConsensusRatio := highestClaimPower * 100 / totalPower
highestConsensusRatio := highestClaimPower * 100
remainingPossibleClaimPower := totalPower - totalClaimsPower
highestPossibleClaimPower := highestClaimPower + remainingPossibleClaimPower
highestPossibleConsensusRatio := highestPossibleClaimPower * 100 / totalPower
olog.Info("processCompletion", "highestConsensusRatio", highestConsensusRatio, "ConsensusThreshold", k.ConsensusThreshold, "highestPossibleConsensusRatio", highestPossibleConsensusRatio)
if highestConsensusRatio >= k.ConsensusThreshold {
if claimType == int64(types.LOCK_CLAIM_TYPE) {
prophecy.Status.Text = StatusText(types.EthBridgeStatus_SuccessStatusText)
} else if claimType == int64(types.BURN_CLAIM_TYPE) {
prophecy.Status.Text = StatusText(types.EthBridgeStatus_WithdrawedStatusText)
}
highestPossibleConsensusRatio := highestPossibleClaimPower * 100
olog.Info("processCompletion", "highestConsensusRatio", highestConsensusRatio/totalPower, "ConsensusThreshold", k.ConsensusThreshold, "highestPossibleConsensusRatio", highestPossibleConsensusRatio/totalPower)
if highestConsensusRatio >= k.ConsensusThreshold*totalPower {
prophecy.Status.Text = types.EthBridgeStatus_SuccessStatusText
prophecy.Status.FinalClaim = highestClaim
} else if highestPossibleConsensusRatio < k.ConsensusThreshold {
prophecy.Status.Text = StatusText(types.EthBridgeStatus_FailedStatusText)
} else if highestPossibleConsensusRatio < k.ConsensusThreshold*totalPower {
prophecy.Status.Text = types.EthBridgeStatus_FailedStatusText
}
return *prophecy, nil
return prophecy, nil
}
// Load the last total validator power.
func (k *Keeper) GetLastTotalPower() (int64, error) {
func (k *OracleKeeper) GetLastTotalPower() (int64, error) {
b, err := k.db.Get(types.CalLastTotalPowerPrefix())
if err != nil && err != types2.ErrNotFound {
return 0, err
......@@ -283,7 +199,7 @@ func (k *Keeper) GetLastTotalPower() (int64, error) {
return 0, nil
}
var powers types.ReceiptQueryTotalPower
err = json.Unmarshal(b, &powers)
err = proto.Unmarshal(b, &powers)
if err != nil {
return 0, types2.ErrUnmarshal
}
......@@ -291,19 +207,19 @@ func (k *Keeper) GetLastTotalPower() (int64, error) {
}
// Set the last total validator power.
func (k *Keeper) SetLastTotalPower() error {
func (k *OracleKeeper) SetLastTotalPower() error {
var totalPower int64
validatorArrays, err := k.GetValidatorArray()
if err != nil {
return err
}
for _, validator := range validatorArrays {
for _, validator := range validatorArrays.Validators {
totalPower += validator.Power
}
totalP := types.ReceiptQueryTotalPower{
TotalPower: totalPower,
}
totalPBytes, _ := json.Marshal(totalP)
totalPBytes, _ := proto.Marshal(&totalP)
err = k.db.Set(types.CalLastTotalPowerPrefix(), totalPBytes)
if err != nil {
return types.ErrSetKV
......@@ -311,25 +227,25 @@ func (k *Keeper) SetLastTotalPower() error {
return nil
}
func (k *Keeper) GetValidatorArray() ([]types.MsgValidator, error) {
func (k *OracleKeeper) GetValidatorArray() (*types.ValidatorList, error) {
validatorsBytes, err := k.db.Get(types.CalValidatorMapsPrefix())
if err != nil {
return nil, err
}
var validatorArrays []types.MsgValidator
err = json.Unmarshal(validatorsBytes, &validatorArrays)
var validatorArrays types.ValidatorList
err = proto.Unmarshal(validatorsBytes, &validatorArrays)
if err != nil {
return nil, types2.ErrUnmarshal
}
return validatorArrays, nil
return &validatorArrays, nil
}
func (k *Keeper) SetConsensusThreshold(ConsensusThreshold int64) {
func (k *OracleKeeper) SetConsensusThreshold(ConsensusThreshold int64) {
k.ConsensusThreshold = ConsensusThreshold
olog.Info("SetConsensusNeeded", "nowConsensusNeeded", k.ConsensusThreshold)
return
}
func (k *Keeper) GetConsensusThreshold() int64 {
func (k *OracleKeeper) GetConsensusThreshold() int64 {
return k.ConsensusThreshold
}
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 {
//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
}
package executor
import (
"encoding/json"
"github.com/golang/protobuf/proto"
"strconv"
"strings"
......@@ -59,120 +59,88 @@ type action struct {
keeper ethbridge.Keeper
}
//todo
//补充不同token的decimal数据库存储
func newAction(a *x2ethereum, tx *chain33types.Transaction, index int32) (*action, bool) {
var defaultCon = false
func newAction(a *x2ethereum, tx *chain33types.Transaction, index int32) *action {
hash := tx.Hash()
fromaddr := tx.From()
var ConsensusThreshold int64
consensusNeededBytes, err := a.GetStateDB().Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
ConsensusThreshold = types2.DefaultConsensusNeeded
cb, _ := json.Marshal(types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: 0,
NowConsensusThreshold: ConsensusThreshold,
})
_ = a.GetStateDB().Set(types2.CalConsensusThresholdPrefix(), cb)
defaultCon = true
} else {
return nil, false
}
} else {
var mc types2.ReceiptSetConsensusThreshold
_ = json.Unmarshal(consensusNeededBytes, &mc)
ConsensusThreshold = mc.NowConsensusThreshold
}
oracleKeeper := oracle.NewKeeper(a.GetStateDB(), ConsensusThreshold)
oracleKeeper := oracle.NewOracleKeeper(a.GetStateDB(), types2.DefaultConsensusNeeded)
if oracleKeeper == nil {
return nil, true
return nil
}
elog.Info("newAction", "newAction", "done")
return &action{a.GetAPI(), a.GetCoinsAccount(), a.GetStateDB(), hash, fromaddr,
a.GetBlockTime(), a.GetHeight(), index, address.ExecAddress(string(tx.Execer)), ethbridge.NewKeeper(oracleKeeper, a.GetStateDB())}, defaultCon
a.GetBlockTime(), a.GetHeight(), index, address.ExecAddress(string(tx.Execer)), ethbridge.NewKeeper(*oracleKeeper, a.GetStateDB())}
}
// ethereum ---> chain33
// lock
func (a *action) procMsgEth2Chain33(ethBridgeClaim *types2.Eth2Chain33, defaultCon bool) (*chain33types.Receipt, error) {
func (a *action) procMsgEth2Chain33(ethBridgeClaim *types2.Eth2Chain33) (*chain33types.Receipt, error) {
receipt := new(chain33types.Receipt)
ethBridgeClaim.LocalCoinSymbol = strings.ToLower(ethBridgeClaim.LocalCoinSymbol)
msgEthBridgeClaim := ethbridge.NewMsgCreateEthBridgeClaim(*ethBridgeClaim)
if err := msgEthBridgeClaim.ValidateBasic(); err != nil {
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
status, err := a.keeper.ProcessClaim(*ethBridgeClaim)
if err != nil {
return nil, err
}
ID := strconv.Itoa(int(msgEthBridgeClaim.EthereumChainID)) + strconv.Itoa(int(msgEthBridgeClaim.Nonce)) + msgEthBridgeClaim.EthereumSender + "lock"
ID := strconv.Itoa(int(ethBridgeClaim.EthereumChainID)) + strconv.Itoa(int(ethBridgeClaim.Nonce)) + ethBridgeClaim.EthereumSender + ethBridgeClaim.TokenContractAddress + "lock"
//记录ethProphecy
bz, err := a.db.Get(types2.CalProphecyPrefix())
bz, err := a.db.Get(types2.CalProphecyPrefix(ID))
if err != nil {
return nil, types2.ErrProphecyGet
}
var dbProphecys []oracle.DBProphecy
var dbProphecy oracle.DBProphecy
err = json.Unmarshal(bz, &dbProphecys)
var dbProphecy types2.ReceiptEthProphecy
err = proto.Unmarshal(bz, &dbProphecy)
if err != nil {
return nil, chain33types.ErrUnmarshal
}
for _, p := range dbProphecys {
if p.ID == ID {
dbProphecy = p
break
}
}
dRes, err := dbProphecy.DeserializeFromDB()
if err != nil {
return nil, err
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalProphecyPrefix(),
Key: types2.CalProphecyPrefix(ID),
Value: bz,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TyProphecyLog, Log: chain33types.Encode(&types2.ReceiptEthProphecy{
ID: dRes.ID,
Status: &types2.ProphecyStatus{
Text: types2.EthBridgeStatus(dRes.Status.Text),
FinalClaim: dRes.Status.FinalClaim,
},
ClaimValidators: dRes.ClaimValidators,
ValidatorClaims: dRes.ValidatorClaims,
})})
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TyProphecyLog, Log: chain33types.Encode(&dbProphecy)})
if status.Text == oracle.StatusText(types2.EthBridgeStatus_SuccessStatusText) {
if status.Text == types2.EthBridgeStatus_SuccessStatusText {
// mavl-x2ethereum-eth
accDB, err := account.NewAccountDB(a.api.GetConfig(), msgEthBridgeClaim.LocalCoinExec, strings.ToLower(msgEthBridgeClaim.LocalCoinSymbol+msgEthBridgeClaim.TokenContractAddress), a.db)
// 这里为了区分相同tokensymbol不同tokenAddress做了级联处理
accDB, err := account.NewAccountDB(a.api.GetConfig(), ethBridgeClaim.LocalCoinExec, strings.ToLower(ethBridgeClaim.LocalCoinSymbol+ethBridgeClaim.TokenContractAddress), a.db)
if err != nil {
return nil, errors.Wrapf(err, "relay procMsgEth2Chain33,exec=%s,sym=%s", msgEthBridgeClaim.LocalCoinExec, msgEthBridgeClaim.LocalCoinSymbol)
return nil, errors.Wrapf(err, "relay procMsgEth2Chain33,exec=%s,sym=%s", ethBridgeClaim.LocalCoinExec, ethBridgeClaim.LocalCoinSymbol)
}
r, err := a.keeper.ProcessSuccessfulClaimForLock(status.FinalClaim, a.execaddr, ethBridgeClaim.LocalCoinSymbol, ethBridgeClaim.TokenContractAddress, accDB)
......@@ -183,28 +151,28 @@ func (a *action) procMsgEth2Chain33(ethBridgeClaim *types2.Eth2Chain33, defaultC
receipt.Logs = append(receipt.Logs, r.Logs...)
//记录成功lock的日志
msgEthBridgeClaimBytes, err := json.Marshal(msgEthBridgeClaim)
msgEthBridgeClaimBytes, err := proto.Marshal(ethBridgeClaim)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{Key: types2.CalEth2Chain33Prefix(), Value: msgEthBridgeClaimBytes})
execlog := &chain33types.ReceiptLog{Ty: types2.TyEth2Chain33Log, Log: chain33types.Encode(&types2.ReceiptEth2Chain33{
EthereumChainID: msgEthBridgeClaim.EthereumChainID,
BridgeContractAddress: msgEthBridgeClaim.BridgeContractAddress,
Nonce: msgEthBridgeClaim.Nonce,
LocalCoinSymbol: msgEthBridgeClaim.LocalCoinSymbol,
LocalCoinExec: msgEthBridgeClaim.LocalCoinExec,
TokenContractAddress: msgEthBridgeClaim.TokenContractAddress,
EthereumSender: msgEthBridgeClaim.EthereumSender,
Chain33Receiver: msgEthBridgeClaim.Chain33Receiver,
ValidatorAddress: msgEthBridgeClaim.ValidatorAddress,
Amount: msgEthBridgeClaim.Amount,
ClaimType: msgEthBridgeClaim.ClaimType,
EthereumChainID: ethBridgeClaim.EthereumChainID,
BridgeContractAddress: ethBridgeClaim.BridgeContractAddress,
Nonce: ethBridgeClaim.Nonce,
LocalCoinSymbol: ethBridgeClaim.LocalCoinSymbol,
LocalCoinExec: ethBridgeClaim.LocalCoinExec,
TokenContractAddress: ethBridgeClaim.TokenContractAddress,
EthereumSender: ethBridgeClaim.EthereumSender,
Chain33Receiver: ethBridgeClaim.Chain33Receiver,
ValidatorAddress: ethBridgeClaim.ValidatorAddress,
Amount: ethBridgeClaim.Amount,
ClaimType: ethBridgeClaim.ClaimType,
XTxHash: a.txhash,
XHeight: uint64(a.height),
ProphecyID: ID,
Decimals: msgEthBridgeClaim.Decimals,
Decimals: ethBridgeClaim.Decimals,
})}
receipt.Logs = append(receipt.Logs, execlog)
......@@ -216,13 +184,46 @@ func (a *action) procMsgEth2Chain33(ethBridgeClaim *types2.Eth2Chain33, defaultC
// chain33 -> ethereum
// 返还在chain33上生成的erc20代币
func (a *action) procMsgBurn(msgBurn *types2.Chain33ToEth, defaultCon bool) (*chain33types.Receipt, error) {
func (a *action) procMsgBurn(msgBurn *types2.Chain33ToEth) (*chain33types.Receipt, error) {
msgBurn.LocalCoinExec = types2.X2ethereumX
receipt := new(chain33types.Receipt)
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
accDB, err := account.NewAccountDB(a.api.GetConfig(), msgBurn.LocalCoinExec, strings.ToLower(msgBurn.LocalCoinSymbol+msgBurn.TokenContract), a.db)
if err != nil {
return nil, errors.Wrapf(err, "relay procMsgBurn,exec=%s,sym=%s", msgBurn.LocalCoinExec, msgBurn.LocalCoinSymbol)
}
receipt, err := a.keeper.ProcessBurn(a.fromaddr, a.execaddr, msgBurn.Amount, msgBurn.TokenContract, msgBurn.Decimals, accDB)
receipt, err = a.keeper.ProcessBurn(a.fromaddr, a.execaddr, msgBurn.Amount, msgBurn.TokenContract, msgBurn.Decimals, accDB)
if err != nil {
return nil, err
}
......@@ -237,20 +238,25 @@ func (a *action) procMsgBurn(msgBurn *types2.Chain33ToEth, defaultCon bool) (*ch
})}
receipt.Logs = append(receipt.Logs, execlog)
msgBurnBytes, err := json.Marshal(msgBurn)
msgBurnBytes, err := proto.Marshal(msgBurn)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{Key: types2.CalWithdrawChain33Prefix(), Value: msgBurnBytes})
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procMsgLock(msgLock *types2.Chain33ToEth) (*chain33types.Receipt, error) {
msgLock.LocalCoinExec = types2.X2ethereumX
receipt := new(chain33types.Receipt)
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
......@@ -258,18 +264,28 @@ func (a *action) procMsgBurn(msgBurn *types2.Chain33ToEth, defaultCon bool) (*ch
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procMsgLock(msgLock *types2.Chain33ToEth, defaultCon bool) (*chain33types.Receipt, error) {
msgLock.LocalCoinExec = types2.X2ethereumX
accDB := account.NewCoinsAccount(a.api.GetConfig())
accDB.SetDB(a.db)
receipt, err := a.keeper.ProcessLock(a.fromaddr, address.ExecAddress(msgLock.LocalCoinSymbol), a.execaddr, msgLock.Amount, accDB)
receipt, err = a.keeper.ProcessLock(a.fromaddr, address.ExecAddress(msgLock.LocalCoinSymbol), a.execaddr, msgLock.Amount, accDB)
if err != nil {
return nil, err
}
......@@ -284,108 +300,79 @@ func (a *action) procMsgLock(msgLock *types2.Chain33ToEth, defaultCon bool) (*ch
})}
receipt.Logs = append(receipt.Logs, execlog)
msgLockBytes, err := json.Marshal(msgLock)
msgLockBytes, err := proto.Marshal(msgLock)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{Key: types2.CalChain33ToEthPrefix(), Value: msgLockBytes})
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
}
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
// ethereum -> chain33
// burn
func (a *action) procWithdrawEth(withdrawEth *types2.Eth2Chain33, defaultCon bool) (*chain33types.Receipt, error) {
func (a *action) procWithdrawEth(withdrawEth *types2.Eth2Chain33) (*chain33types.Receipt, error) {
elog.Info("procWithdrawEth", "receive a procWithdrawEth tx", "start")
receipt := new(chain33types.Receipt)
msgWithdrawEth := ethbridge.NewMsgCreateEthBridgeClaim(*withdrawEth)
if err := msgWithdrawEth.ValidateBasic(); err != nil {
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
status, err := a.keeper.ProcessClaim(*withdrawEth)
if err != nil {
return nil, err
}
ID := strconv.Itoa(int(msgWithdrawEth.EthereumChainID)) + strconv.Itoa(int(msgWithdrawEth.Nonce)) + msgWithdrawEth.EthereumSender + "burn"
ID := strconv.Itoa(int(withdrawEth.EthereumChainID)) + strconv.Itoa(int(withdrawEth.Nonce)) + withdrawEth.EthereumSender + withdrawEth.TokenContractAddress + "burn"
//记录ethProphecy
bz, err := a.db.Get(types2.CalProphecyPrefix())
bz, err := a.db.Get(types2.CalProphecyPrefix(ID))
if err != nil {
return nil, types2.ErrProphecyGet
}
var dbProphecys []oracle.DBProphecy
var dbProphecy oracle.DBProphecy
err = json.Unmarshal(bz, &dbProphecys)
var dbProphecy types2.ReceiptEthProphecy
err = proto.Unmarshal(bz, &dbProphecy)
if err != nil {
return nil, chain33types.ErrUnmarshal
}
for _, p := range dbProphecys {
if p.ID == ID {
dbProphecy = p
break
}
}
dRes, err := dbProphecy.DeserializeFromDB()
if err != nil {
return nil, err
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalProphecyPrefix(),
Key: types2.CalProphecyPrefix(ID),
Value: bz,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TyProphecyLog, Log: chain33types.Encode(&types2.ReceiptEthProphecy{
ID: dRes.ID,
Status: &types2.ProphecyStatus{
Text: types2.EthBridgeStatus(dRes.Status.Text),
FinalClaim: dRes.Status.FinalClaim,
},
ClaimValidators: dRes.ClaimValidators,
ValidatorClaims: dRes.ValidatorClaims,
})})
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TyProphecyLog, Log: chain33types.Encode(&dbProphecy)})
if status.Text == oracle.StatusText(types2.EthBridgeStatus_WithdrawedStatusText) {
if status.Text == types2.EthBridgeStatus_SuccessStatusText {
accDB := account.NewCoinsAccount(a.api.GetConfig())
accDB.SetDB(a.db)
r, err := a.keeper.ProcessSuccessfulClaimForBurn(status.FinalClaim, a.execaddr, withdrawEth.LocalCoinSymbol, accDB)
......@@ -395,28 +382,28 @@ func (a *action) procWithdrawEth(withdrawEth *types2.Eth2Chain33, defaultCon boo
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
msgWithdrawEthBytes, err := json.Marshal(msgWithdrawEth)
msgWithdrawEthBytes, err := proto.Marshal(withdrawEth)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{Key: types2.CalWithdrawEthPrefix(), Value: msgWithdrawEthBytes})
execlog := &chain33types.ReceiptLog{Ty: types2.TyWithdrawEthLog, Log: chain33types.Encode(&types2.ReceiptEth2Chain33{
EthereumChainID: msgWithdrawEth.EthereumChainID,
BridgeContractAddress: msgWithdrawEth.BridgeContractAddress,
Nonce: msgWithdrawEth.Nonce,
LocalCoinSymbol: msgWithdrawEth.LocalCoinSymbol,
LocalCoinExec: msgWithdrawEth.LocalCoinExec,
TokenContractAddress: msgWithdrawEth.TokenContractAddress,
EthereumSender: msgWithdrawEth.EthereumSender,
Chain33Receiver: msgWithdrawEth.Chain33Receiver,
ValidatorAddress: msgWithdrawEth.ValidatorAddress,
Amount: msgWithdrawEth.Amount,
ClaimType: msgWithdrawEth.ClaimType,
EthereumChainID: withdrawEth.EthereumChainID,
BridgeContractAddress: withdrawEth.BridgeContractAddress,
Nonce: withdrawEth.Nonce,
LocalCoinSymbol: withdrawEth.LocalCoinSymbol,
LocalCoinExec: withdrawEth.LocalCoinExec,
TokenContractAddress: withdrawEth.TokenContractAddress,
EthereumSender: withdrawEth.EthereumSender,
Chain33Receiver: withdrawEth.Chain33Receiver,
ValidatorAddress: withdrawEth.ValidatorAddress,
Amount: withdrawEth.Amount,
ClaimType: withdrawEth.ClaimType,
XTxHash: a.txhash,
XHeight: uint64(a.height),
ProphecyID: ID,
Decimals: msgWithdrawEth.Decimals,
Decimals: withdrawEth.Decimals,
})}
receipt.Logs = append(receipt.Logs, execlog)
......@@ -426,33 +413,48 @@ func (a *action) procWithdrawEth(withdrawEth *types2.Eth2Chain33, defaultCon boo
return receipt, nil
}
func (a *action) procMsgTransfer(msgTransfer *chain33types.AssetsTransfer, defaultCon bool) (*chain33types.Receipt, error) {
func (a *action) procMsgTransfer(msgTransfer *chain33types.AssetsTransfer) (*chain33types.Receipt, error) {
token := msgTransfer.GetCointoken()
accDB, err := account.NewAccountDB(a.api.GetConfig(), types2.X2ethereumX, token, a.db)
receipt := new(chain33types.Receipt)
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
return nil, err
}
receipt, err := accDB.ExecTransfer(a.fromaddr, msgTransfer.To, address.ExecAddress(types2.X2ethereumX), msgTransfer.Amount)
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, err
return nil, chain33types.ErrMarshal
}
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
return nil, err
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
}
accDB, err := account.NewAccountDB(a.api.GetConfig(), types2.X2ethereumX, token, a.db)
if err != nil {
return nil, err
}
receipt, err = accDB.ExecTransfer(a.fromaddr, msgTransfer.To, address.ExecAddress(types2.X2ethereumX), msgTransfer.Amount)
if err != nil {
return nil, err
}
receipt.Ty = chain33types.ExecOk
......@@ -462,10 +464,46 @@ func (a *action) procMsgTransfer(msgTransfer *chain33types.AssetsTransfer, defau
//需要一笔交易来注册validator
//这里注册的validator的power之和可能不为1,需要在内部进行加权
//返回的回执中,KV包含所有validator的power值,Log中包含本次注册的validator的power值
func (a *action) procAddValidator(msgAddValidator *types2.MsgValidator, defaultCon bool) (*chain33types.Receipt, error) {
func (a *action) procAddValidator(msgAddValidator *types2.MsgValidator) (*chain33types.Receipt, error) {
elog.Info("procAddValidator", "start", msgAddValidator)
receipt := new(chain33types.Receipt)
receipt, err := a.keeper.ProcessAddValidator(msgAddValidator.Address, msgAddValidator.Power)
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
if !types2.CheckPower(msgAddValidator.Power) {
return nil, types2.ErrInvalidPower
}
receipt, err = a.keeper.ProcessAddValidator(msgAddValidator.Address, msgAddValidator.Power)
if err != nil {
return nil, err
}
......@@ -478,14 +516,18 @@ func (a *action) procAddValidator(msgAddValidator *types2.MsgValidator, defaultC
})}
receipt.Logs = append(receipt.Logs, execlog)
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procRemoveValidator(msgRemoveValidator *types2.MsgValidator) (*chain33types.Receipt, error) {
receipt := new(chain33types.Receipt)
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
......@@ -493,17 +535,26 @@ func (a *action) procAddValidator(msgAddValidator *types2.MsgValidator, defaultC
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procRemoveValidator(msgRemoveValidator *types2.MsgValidator, defaultCon bool) (*chain33types.Receipt, error) {
receipt := new(chain33types.Receipt)
receipt, err := a.keeper.ProcessRemoveValidator(msgRemoveValidator.Address)
receipt, err = a.keeper.ProcessRemoveValidator(msgRemoveValidator.Address)
if err != nil {
return nil, err
}
......@@ -516,14 +567,18 @@ func (a *action) procRemoveValidator(msgRemoveValidator *types2.MsgValidator, de
})}
receipt.Logs = append(receipt.Logs, execlog)
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procModifyValidator(msgModifyValidator *types2.MsgValidator) (*chain33types.Receipt, error) {
receipt := new(chain33types.Receipt)
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
......@@ -531,17 +586,30 @@ func (a *action) procRemoveValidator(msgRemoveValidator *types2.MsgValidator, de
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procModifyValidator(msgModifyValidator *types2.MsgValidator, defaultCon bool) (*chain33types.Receipt, error) {
receipt := new(chain33types.Receipt)
if !types2.CheckPower(msgModifyValidator.Power) {
return nil, types2.ErrInvalidPower
}
receipt, err := a.keeper.ProcessModifyValidator(msgModifyValidator.Address, msgModifyValidator.Power)
receipt, err = a.keeper.ProcessModifyValidator(msgModifyValidator.Address, msgModifyValidator.Power)
if err != nil {
return nil, err
}
......@@ -554,30 +622,15 @@ func (a *action) procModifyValidator(msgModifyValidator *types2.MsgValidator, de
})}
receipt.Logs = append(receipt.Logs, execlog)
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
}
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procMsgSetConsensusThreshold(msgSetConsensusThreshold *types2.MsgConsensusThreshold) (*chain33types.Receipt, error) {
receipt := new(chain33types.Receipt)
if !types2.CheckPower(msgSetConsensusThreshold.ConsensusThreshold) {
return nil, types2.ErrInvalidPower
}
preConsensusNeeded, nowConsensusNeeded, err := a.keeper.ProcessSetConsensusNeeded(msgSetConsensusThreshold.ConsensusThreshold)
if err != nil {
......@@ -593,7 +646,9 @@ func (a *action) procMsgSetConsensusThreshold(msgSetConsensusThreshold *types2.M
execlog := &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)}
receipt.Logs = append(receipt.Logs, execlog)
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
msgSetConsensusThresholdBytes, err := proto.Marshal(&types2.ReceiptQueryConsensusThreshold{
ConsensusThreshold: nowConsensusNeeded,
})
if err != nil {
return nil, chain33types.ErrMarshal
}
......
......@@ -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
}
......@@ -6,11 +6,10 @@ package types
import (
context "context"
fmt "fmt"
math "math"
types "github.com/33cn/chain33/types"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
......@@ -30,21 +29,18 @@ const (
EthBridgeStatus_PendingStatusText EthBridgeStatus = 0
EthBridgeStatus_SuccessStatusText EthBridgeStatus = 1
EthBridgeStatus_FailedStatusText EthBridgeStatus = 2
EthBridgeStatus_WithdrawedStatusText EthBridgeStatus = 3
)
var EthBridgeStatus_name = map[int32]string{
0: "PendingStatusText",
1: "SuccessStatusText",
2: "FailedStatusText",
3: "WithdrawedStatusText",
}
var EthBridgeStatus_value = map[string]int32{
"PendingStatusText": 0,
"SuccessStatusText": 1,
"FailedStatusText": 2,
"WithdrawedStatusText": 3,
}
func (x EthBridgeStatus) String() string {
......@@ -1207,6 +1203,45 @@ func (m *StringMap) GetValidators() []string {
return nil
}
type ValidatorList struct {
Validators []*MsgValidator `protobuf:"bytes,1,rep,name=validators,proto3" json:"validators,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ValidatorList) Reset() { *m = ValidatorList{} }
func (m *ValidatorList) String() string { return proto.CompactTextString(m) }
func (*ValidatorList) ProtoMessage() {}
func (*ValidatorList) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{15}
}
func (m *ValidatorList) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ValidatorList.Unmarshal(m, b)
}
func (m *ValidatorList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ValidatorList.Marshal(b, m, deterministic)
}
func (m *ValidatorList) XXX_Merge(src proto.Message) {
xxx_messageInfo_ValidatorList.Merge(m, src)
}
func (m *ValidatorList) XXX_Size() int {
return xxx_messageInfo_ValidatorList.Size(m)
}
func (m *ValidatorList) XXX_DiscardUnknown() {
xxx_messageInfo_ValidatorList.DiscardUnknown(m)
}
var xxx_messageInfo_ValidatorList proto.InternalMessageInfo
func (m *ValidatorList) GetValidators() []*MsgValidator {
if m != nil {
return m.Validators
}
return nil
}
type ProphecyStatus struct {
Text EthBridgeStatus `protobuf:"varint,1,opt,name=Text,proto3,enum=types.EthBridgeStatus" json:"Text,omitempty"`
FinalClaim string `protobuf:"bytes,2,opt,name=FinalClaim,proto3" json:"FinalClaim,omitempty"`
......@@ -1219,7 +1254,7 @@ func (m *ProphecyStatus) Reset() { *m = ProphecyStatus{} }
func (m *ProphecyStatus) String() string { return proto.CompactTextString(m) }
func (*ProphecyStatus) ProtoMessage() {}
func (*ProphecyStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{15}
return fileDescriptor_1dd1834a817ceb21, []int{16}
}
func (m *ProphecyStatus) XXX_Unmarshal(b []byte) error {
......@@ -1265,7 +1300,7 @@ func (m *QueryValidatorsParams) Reset() { *m = QueryValidatorsParams{} }
func (m *QueryValidatorsParams) String() string { return proto.CompactTextString(m) }
func (*QueryValidatorsParams) ProtoMessage() {}
func (*QueryValidatorsParams) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{16}
return fileDescriptor_1dd1834a817ceb21, []int{17}
}
func (m *QueryValidatorsParams) XXX_Unmarshal(b []byte) error {
......@@ -1305,7 +1340,7 @@ func (m *ReceiptQueryValidator) Reset() { *m = ReceiptQueryValidator{} }
func (m *ReceiptQueryValidator) String() string { return proto.CompactTextString(m) }
func (*ReceiptQueryValidator) ProtoMessage() {}
func (*ReceiptQueryValidator) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{17}
return fileDescriptor_1dd1834a817ceb21, []int{18}
}
func (m *ReceiptQueryValidator) XXX_Unmarshal(b []byte) error {
......@@ -1350,7 +1385,7 @@ func (m *QueryTotalPowerParams) Reset() { *m = QueryTotalPowerParams{} }
func (m *QueryTotalPowerParams) String() string { return proto.CompactTextString(m) }
func (*QueryTotalPowerParams) ProtoMessage() {}
func (*QueryTotalPowerParams) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{18}
return fileDescriptor_1dd1834a817ceb21, []int{19}
}
func (m *QueryTotalPowerParams) XXX_Unmarshal(b []byte) error {
......@@ -1382,7 +1417,7 @@ func (m *ReceiptQueryTotalPower) Reset() { *m = ReceiptQueryTotalPower{}
func (m *ReceiptQueryTotalPower) String() string { return proto.CompactTextString(m) }
func (*ReceiptQueryTotalPower) ProtoMessage() {}
func (*ReceiptQueryTotalPower) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{19}
return fileDescriptor_1dd1834a817ceb21, []int{20}
}
func (m *ReceiptQueryTotalPower) XXX_Unmarshal(b []byte) error {
......@@ -1420,7 +1455,7 @@ func (m *QueryConsensusThresholdParams) Reset() { *m = QueryConsensusThr
func (m *QueryConsensusThresholdParams) String() string { return proto.CompactTextString(m) }
func (*QueryConsensusThresholdParams) ProtoMessage() {}
func (*QueryConsensusThresholdParams) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{20}
return fileDescriptor_1dd1834a817ceb21, []int{21}
}
func (m *QueryConsensusThresholdParams) XXX_Unmarshal(b []byte) error {
......@@ -1452,7 +1487,7 @@ func (m *ReceiptQueryConsensusThreshold) Reset() { *m = ReceiptQueryCons
func (m *ReceiptQueryConsensusThreshold) String() string { return proto.CompactTextString(m) }
func (*ReceiptQueryConsensusThreshold) ProtoMessage() {}
func (*ReceiptQueryConsensusThreshold) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{21}
return fileDescriptor_1dd1834a817ceb21, []int{22}
}
func (m *ReceiptQueryConsensusThreshold) XXX_Unmarshal(b []byte) error {
......@@ -1495,7 +1530,7 @@ func (m *QuerySymbolAssetsByTxTypeParams) Reset() { *m = QuerySymbolAsse
func (m *QuerySymbolAssetsByTxTypeParams) String() string { return proto.CompactTextString(m) }
func (*QuerySymbolAssetsByTxTypeParams) ProtoMessage() {}
func (*QuerySymbolAssetsByTxTypeParams) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{22}
return fileDescriptor_1dd1834a817ceb21, []int{23}
}
func (m *QuerySymbolAssetsByTxTypeParams) XXX_Unmarshal(b []byte) error {
......@@ -1562,7 +1597,7 @@ func (m *ReceiptQuerySymbolAssets) Reset() { *m = ReceiptQuerySymbolAsse
func (m *ReceiptQuerySymbolAssets) String() string { return proto.CompactTextString(m) }
func (*ReceiptQuerySymbolAssets) ProtoMessage() {}
func (*ReceiptQuerySymbolAssets) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{23}
return fileDescriptor_1dd1834a817ceb21, []int{24}
}
func (m *ReceiptQuerySymbolAssets) XXX_Unmarshal(b []byte) error {
......@@ -1605,7 +1640,7 @@ func (m *ReceiptQuerySymbolAssetsByTxType) Reset() { *m = ReceiptQuerySy
func (m *ReceiptQuerySymbolAssetsByTxType) String() string { return proto.CompactTextString(m) }
func (*ReceiptQuerySymbolAssetsByTxType) ProtoMessage() {}
func (*ReceiptQuerySymbolAssetsByTxType) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{24}
return fileDescriptor_1dd1834a817ceb21, []int{25}
}
func (m *ReceiptQuerySymbolAssetsByTxType) XXX_Unmarshal(b []byte) error {
......@@ -1674,7 +1709,7 @@ func (m *QueryRelayerBalance) Reset() { *m = QueryRelayerBalance{} }
func (m *QueryRelayerBalance) String() string { return proto.CompactTextString(m) }
func (*QueryRelayerBalance) ProtoMessage() {}
func (*QueryRelayerBalance) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{25}
return fileDescriptor_1dd1834a817ceb21, []int{26}
}
func (m *QueryRelayerBalance) XXX_Unmarshal(b []byte) error {
......@@ -1727,7 +1762,7 @@ func (m *ReceiptQueryRelayerBalance) Reset() { *m = ReceiptQueryRelayerB
func (m *ReceiptQueryRelayerBalance) String() string { return proto.CompactTextString(m) }
func (*ReceiptQueryRelayerBalance) ProtoMessage() {}
func (*ReceiptQueryRelayerBalance) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{26}
return fileDescriptor_1dd1834a817ceb21, []int{27}
}
func (m *ReceiptQueryRelayerBalance) XXX_Unmarshal(b []byte) error {
......@@ -1768,7 +1803,7 @@ func (m *ReceiptQueryRelayerBalanceForOneToken) Reset() { *m = ReceiptQu
func (m *ReceiptQueryRelayerBalanceForOneToken) String() string { return proto.CompactTextString(m) }
func (*ReceiptQueryRelayerBalanceForOneToken) ProtoMessage() {}
func (*ReceiptQueryRelayerBalanceForOneToken) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{27}
return fileDescriptor_1dd1834a817ceb21, []int{28}
}
func (m *ReceiptQueryRelayerBalanceForOneToken) XXX_Unmarshal(b []byte) error {
......@@ -1821,7 +1856,7 @@ func (m *ReceiptTokenToTokenAddress) Reset() { *m = ReceiptTokenToTokenA
func (m *ReceiptTokenToTokenAddress) String() string { return proto.CompactTextString(m) }
func (*ReceiptTokenToTokenAddress) ProtoMessage() {}
func (*ReceiptTokenToTokenAddress) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{28}
return fileDescriptor_1dd1834a817ceb21, []int{29}
}
func (m *ReceiptTokenToTokenAddress) XXX_Unmarshal(b []byte) error {
......@@ -1866,6 +1901,7 @@ func init() {
proto.RegisterType((*ClaimValidators)(nil), "types.ClaimValidators")
proto.RegisterType((*ValidatorClaims)(nil), "types.ValidatorClaims")
proto.RegisterType((*StringMap)(nil), "types.StringMap")
proto.RegisterType((*ValidatorList)(nil), "types.ValidatorList")
proto.RegisterType((*ProphecyStatus)(nil), "types.ProphecyStatus")
proto.RegisterType((*QueryValidatorsParams)(nil), "types.QueryValidatorsParams")
proto.RegisterType((*ReceiptQueryValidator)(nil), "types.ReceiptQueryValidator")
......@@ -1887,91 +1923,92 @@ func init() {
}
var fileDescriptor_1dd1834a817ceb21 = []byte{
// 1344 bytes of a gzipped FileDescriptorProto
// 1346 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x58, 0xcb, 0x6e, 0xdb, 0x46,
0x17, 0x36, 0x45, 0x49, 0x0e, 0x8f, 0x14, 0x5b, 0x99, 0x58, 0xfe, 0x09, 0xc3, 0x7f, 0x22, 0x10,
0xbd, 0x18, 0x69, 0x6b, 0x14, 0x76, 0x7a, 0xc9, 0x26, 0x8d, 0x2d, 0x2b, 0x75, 0x16, 0x69, 0xdc,
0x11, 0x7b, 0x03, 0xb2, 0x19, 0x93, 0x13, 0x93, 0x28, 0x45, 0x0a, 0xe4, 0xc8, 0x96, 0x96, 0xdd,
0x76, 0xd5, 0x57, 0x69, 0x97, 0x5d, 0xf4, 0x35, 0xb2, 0xec, 0xab, 0x14, 0x33, 0x1c, 0x92, 0x43,
0x8a, 0x56, 0x8c, 0xa0, 0x8b, 0x16, 0xe8, 0x72, 0xbe, 0x73, 0xfb, 0xce, 0x65, 0x0e, 0x47, 0x82,
0xde, 0xfc, 0x80, 0x32, 0x8f, 0xc6, 0x74, 0x36, 0xd9, 0x9f, 0xc6, 0x11, 0x8b, 0x50, 0x8b, 0x2d,
0xa6, 0x34, 0xd9, 0xb9, 0xc3, 0x62, 0x12, 0x26, 0xc4, 0x61, 0x7e, 0x14, 0xa6, 0x92, 0x9d, 0xdb,
0xc4, 0x71, 0xa2, 0x59, 0xc8, 0xd2, 0xa3, 0xf5, 0xba, 0x09, 0xbd, 0xef, 0x73, 0xeb, 0x23, 0xa1,
0x89, 0x3e, 0x85, 0x0e, 0x65, 0xde, 0xc1, 0xd0, 0x23, 0x7e, 0x78, 0x78, 0x68, 0x6a, 0x03, 0x6d,
0xaf, 0x73, 0x80, 0xf6, 0x85, 0xcf, 0xfd, 0x51, 0x21, 0x39, 0x5d, 0xc3, 0xaa, 0x22, 0xb7, 0xbb,
0xf2, 0x99, 0xe7, 0xc6, 0xe4, 0x6a, 0xc4, 0x3c, 0xb3, 0xb1, 0xca, 0x4e, 0x51, 0x44, 0x5f, 0xc0,
0x66, 0x76, 0xcc, 0x62, 0xea, 0xc2, 0xf6, 0xae, 0xb4, 0x95, 0xa8, 0x1d, 0x8d, 0x98, 0x77, 0xba,
0x86, 0xab, 0xda, 0xe8, 0x11, 0x74, 0x1d, 0x45, 0xc5, 0x6c, 0xae, 0xb2, 0x2e, 0xa9, 0x72, 0x53,
0xe2, 0xba, 0xdf, 0x92, 0xc0, 0x77, 0x09, 0x8b, 0x62, 0xb3, 0x55, 0x32, 0x7d, 0x9e, 0x5c, 0xe4,
0x22, 0x6e, 0xaa, 0xaa, 0x72, 0xda, 0x31, 0x9d, 0x44, 0x97, 0xb4, 0xb0, 0x6e, 0xaf, 0xb2, 0xae,
0x6a, 0xa3, 0xcf, 0xa0, 0x33, 0x89, 0x5c, 0xff, 0xd5, 0xe2, 0x2c, 0xba, 0xa2, 0xb1, 0xb9, 0xbe,
0xca, 0x58, 0xd5, 0x44, 0x36, 0xf4, 0x13, 0xca, 0x86, 0x51, 0x98, 0xd0, 0x30, 0x99, 0x25, 0xb6,
0x17, 0xd3, 0xc4, 0x8b, 0x02, 0xd7, 0xbc, 0x25, 0x5c, 0xec, 0x16, 0x2e, 0x96, 0x75, 0x4e, 0xd7,
0x70, 0xbd, 0x31, 0x3a, 0x84, 0x5b, 0x62, 0x5e, 0x5e, 0xd1, 0xd8, 0x34, 0x84, 0xa3, 0xbe, 0x74,
0x74, 0x94, 0x24, 0x94, 0x25, 0xb6, 0x14, 0x9e, 0xae, 0xe1, 0x5c, 0x11, 0x6d, 0x40, 0x83, 0x2d,
0x4c, 0x18, 0x68, 0x7b, 0x2d, 0xdc, 0x60, 0x8b, 0xe3, 0x75, 0x68, 0x5d, 0x92, 0x60, 0x46, 0xad,
0x2f, 0xa1, 0x5f, 0x1b, 0x1f, 0xed, 0x03, 0x72, 0x96, 0x99, 0xf3, 0x21, 0xd3, 0x71, 0x8d, 0xc4,
0x7a, 0x0c, 0x5d, 0xb5, 0x16, 0xc8, 0x84, 0x75, 0xe2, 0xba, 0x31, 0x4d, 0x12, 0x61, 0x64, 0xe0,
0xec, 0x88, 0xb6, 0xa0, 0x35, 0x15, 0x95, 0x6c, 0x08, 0x67, 0xe9, 0xc1, 0x7a, 0xad, 0x43, 0x47,
0x19, 0x3e, 0xb4, 0x07, 0x9b, 0x23, 0x39, 0xef, 0x02, 0x7a, 0x76, 0x22, 0x83, 0x57, 0x61, 0xf4,
0x10, 0xfa, 0xc7, 0xb1, 0xef, 0x5e, 0xd0, 0x61, 0x14, 0xb2, 0x98, 0x38, 0xec, 0x48, 0xc6, 0x6d,
0x88, 0xb8, 0xf5, 0x42, 0xce, 0xe2, 0xab, 0x28, 0x74, 0xa8, 0x98, 0x61, 0x1d, 0xa7, 0x07, 0x1e,
0x35, 0x88, 0x1c, 0x12, 0x0c, 0x23, 0x3f, 0x1c, 0x2f, 0x26, 0xe7, 0x51, 0x20, 0xa6, 0xd4, 0xc0,
0x55, 0x18, 0xbd, 0x03, 0xb7, 0x73, 0x68, 0x34, 0xa7, 0x8e, 0x18, 0x49, 0x03, 0x97, 0x41, 0x74,
0x00, 0x5b, 0x76, 0xf4, 0x23, 0x0d, 0xab, 0xd4, 0xda, 0x42, 0xb9, 0x56, 0x86, 0xde, 0x83, 0x8d,
0x2c, 0xc5, 0x31, 0x0d, 0x5d, 0x39, 0x72, 0x06, 0xae, 0xa0, 0x9c, 0xab, 0x2c, 0x16, 0xa6, 0x0e,
0xf5, 0x2f, 0x69, 0x2c, 0x06, 0xcb, 0xc0, 0x55, 0x18, 0x3d, 0x80, 0x5e, 0xde, 0x98, 0x8c, 0x81,
0x21, 0x54, 0x97, 0x70, 0xb4, 0x0d, 0xed, 0xa3, 0x09, 0x5f, 0x3d, 0x62, 0x5a, 0x0c, 0x2c, 0x4f,
0x68, 0x17, 0x8c, 0x61, 0x40, 0xfc, 0x89, 0xbd, 0x98, 0x52, 0xb3, 0x23, 0x6a, 0x56, 0x00, 0x68,
0x07, 0x6e, 0x9d, 0x50, 0xc7, 0x9f, 0x90, 0x20, 0x31, 0xbb, 0x42, 0x98, 0x9f, 0xad, 0x5f, 0x34,
0x40, 0x2f, 0x62, 0xe2, 0x04, 0x54, 0xe8, 0xf3, 0x74, 0x69, 0xc8, 0xea, 0xe8, 0x6b, 0xf5, 0xf4,
0x0b, 0x4a, 0x8d, 0xeb, 0x29, 0xe9, 0xab, 0x28, 0x35, 0x2b, 0x94, 0x7e, 0x6e, 0x40, 0x57, 0xdd,
0x37, 0xbc, 0x9b, 0xa5, 0x5e, 0x48, 0x2a, 0x65, 0x90, 0x6b, 0x49, 0x2b, 0xd9, 0x98, 0x94, 0x4f,
0x19, 0xe4, 0xd5, 0xce, 0x3a, 0x95, 0x67, 0xa6, 0xa7, 0xd5, 0xae, 0xe2, 0x4a, 0x6a, 0xcd, 0x52,
0x6a, 0x35, 0x73, 0xd8, 0xba, 0xe1, 0x1c, 0xb6, 0xeb, 0xe6, 0x50, 0x2d, 0xc6, 0x7a, 0xa5, 0x18,
0xbf, 0x35, 0x01, 0x09, 0x42, 0x53, 0xf6, 0xdf, 0x05, 0xfc, 0xb7, 0x5e, 0x40, 0x13, 0xd6, 0xe7,
0xf6, 0xfc, 0x94, 0x24, 0x9e, 0xb8, 0x7f, 0x5d, 0x9c, 0x1d, 0x85, 0xe4, 0x94, 0xfa, 0x17, 0x1e,
0x33, 0x6f, 0x0f, 0xb4, 0xbd, 0x26, 0xce, 0x8e, 0xe8, 0x1e, 0xc0, 0x59, 0x1c, 0x4d, 0x3d, 0xea,
0x2c, 0x9e, 0x9d, 0x98, 0x1b, 0x22, 0x9a, 0x82, 0x94, 0x86, 0x66, 0xb3, 0x32, 0x34, 0x7f, 0x6a,
0x70, 0x57, 0x0e, 0xcd, 0x3f, 0xfa, 0x22, 0xed, 0x82, 0x31, 0x62, 0x5e, 0xe9, 0x0a, 0x15, 0x40,
0x29, 0xc3, 0x76, 0x25, 0xc3, 0x4b, 0xe8, 0xc9, 0x04, 0xdf, 0xfa, 0xa3, 0xa6, 0x76, 0x45, 0xbf,
0xb6, 0x2b, 0xcd, 0x52, 0x57, 0xac, 0x3f, 0x34, 0xd8, 0x95, 0x81, 0xc7, 0xb5, 0x0f, 0x80, 0x87,
0xd0, 0x9f, 0xc6, 0x74, 0x78, 0xdd, 0xc7, 0xb9, 0x5e, 0xc8, 0xad, 0xc2, 0xe8, 0xaa, 0xc6, 0x2a,
0x25, 0x5c, 0x2f, 0x7c, 0xab, 0x04, 0xf6, 0x60, 0xfb, 0xeb, 0x19, 0x8d, 0x17, 0x23, 0xe6, 0x65,
0xc3, 0x74, 0x46, 0x62, 0x32, 0x49, 0xf8, 0x2b, 0x44, 0x6e, 0x11, 0x03, 0x37, 0x9e, 0x9d, 0x58,
0xaf, 0x35, 0x75, 0xf3, 0x64, 0xca, 0x55, 0x35, 0xf4, 0x11, 0xb4, 0xc7, 0x8c, 0xb0, 0x59, 0x22,
0xdf, 0xaa, 0xd9, 0x7b, 0x27, 0x33, 0x48, 0x85, 0x58, 0x2a, 0xa1, 0x27, 0xb0, 0x29, 0xee, 0x45,
0xde, 0xb6, 0xc4, 0xd4, 0x07, 0xfa, 0x5e, 0xe7, 0x60, 0x3b, 0x7b, 0x69, 0x96, 0xa5, 0xb8, 0xaa,
0xce, 0x3d, 0xe4, 0x27, 0x21, 0xe3, 0x5f, 0x10, 0xd5, 0x43, 0x45, 0x8a, 0xab, 0xea, 0xd6, 0x0f,
0x4b, 0x1c, 0xf8, 0x84, 0x38, 0x1c, 0x92, 0x89, 0xa5, 0x07, 0xf4, 0x31, 0xc0, 0x65, 0xc1, 0x33,
0xcd, 0xaf, 0x27, 0xa3, 0x8c, 0x59, 0xec, 0x87, 0x17, 0xcf, 0xc9, 0x14, 0x2b, 0x3a, 0xd6, 0x68,
0x89, 0x1c, 0x1f, 0xf2, 0x5c, 0x41, 0xba, 0x2f, 0x80, 0x22, 0x70, 0x43, 0x09, 0x6c, 0x7d, 0x00,
0x46, 0xee, 0x9f, 0x6f, 0x02, 0x85, 0x85, 0x36, 0xd0, 0xf9, 0x26, 0x50, 0x62, 0xbe, 0x84, 0x8d,
0x72, 0xb1, 0xd1, 0x03, 0x68, 0xda, 0x74, 0x9e, 0x5e, 0xef, 0x8d, 0xbc, 0x2e, 0x23, 0xe6, 0xa5,
0xcb, 0x5e, 0xb6, 0x44, 0xe8, 0x70, 0xef, 0x4f, 0xfd, 0x90, 0x04, 0x43, 0x85, 0x85, 0x82, 0x58,
0x9f, 0x40, 0x5f, 0x0c, 0x4c, 0x51, 0x2c, 0x39, 0x2f, 0x2b, 0xf3, 0xb2, 0x02, 0xe8, 0xcb, 0xe1,
0x29, 0x5b, 0xa3, 0xc3, 0xa5, 0x6c, 0xea, 0xdf, 0xeb, 0x6a, 0x8a, 0x9c, 0x24, 0x8b, 0x18, 0x09,
0xce, 0x94, 0x5b, 0xac, 0x20, 0xd6, 0xff, 0x24, 0x49, 0x3b, 0x87, 0x52, 0x92, 0xd6, 0xe7, 0xb0,
0xad, 0xd2, 0x28, 0xe4, 0x15, 0x97, 0xda, 0x92, 0xcb, 0xfb, 0xf0, 0x7f, 0x61, 0xb2, 0x7c, 0xef,
0xa4, 0xeb, 0x33, 0xb8, 0xa7, 0xba, 0xfe, 0x1b, 0x5e, 0xe9, 0xbf, 0x6a, 0x70, 0x5f, 0xf8, 0x4a,
0x17, 0x60, 0xfa, 0x8b, 0xe1, 0x78, 0x61, 0xcf, 0xf9, 0x47, 0x44, 0x56, 0x7d, 0x00, 0x1d, 0xc6,
0xb7, 0xb5, 0x5c, 0x9a, 0x69, 0xdd, 0x55, 0x88, 0xf7, 0xc5, 0xf5, 0x63, 0x2a, 0x7e, 0x86, 0xca,
0x52, 0x15, 0x00, 0x5f, 0xc5, 0x6c, 0x9e, 0xbf, 0xc9, 0x0c, 0x2c, 0x4f, 0xdc, 0x4a, 0x38, 0xe1,
0x1f, 0x3a, 0xb9, 0xa5, 0x0b, 0x80, 0xef, 0x13, 0x37, 0x5d, 0xbd, 0x62, 0x4d, 0xeb, 0x38, 0x3b,
0x5a, 0xdf, 0x80, 0xa9, 0x56, 0x41, 0x65, 0x8e, 0x1e, 0x81, 0x1e, 0xd3, 0xac, 0xc7, 0xef, 0xcb,
0x1e, 0x5f, 0xa7, 0x9d, 0xe5, 0x89, 0xb9, 0x8d, 0xf5, 0xbb, 0x06, 0x83, 0x37, 0x69, 0xde, 0xa0,
0x16, 0x42, 0x83, 0x91, 0xa0, 0xf4, 0x42, 0x55, 0xa1, 0x55, 0xf5, 0x28, 0xaa, 0xd8, 0xac, 0x56,
0xb1, 0x54, 0xad, 0x56, 0xa5, 0x5a, 0x56, 0x04, 0x77, 0x05, 0x69, 0x4c, 0x03, 0xb2, 0xa0, 0xf1,
0x31, 0x09, 0x08, 0x7f, 0x3d, 0xbd, 0x99, 0xae, 0xf2, 0x05, 0x6b, 0x94, 0xbf, 0x60, 0xa5, 0x80,
0x7a, 0x35, 0xe0, 0x4b, 0xd8, 0x51, 0x8b, 0x55, 0x89, 0xfb, 0x58, 0x6d, 0xc3, 0x87, 0x35, 0x6d,
0x28, 0xeb, 0x3f, 0x8d, 0xe2, 0x17, 0x21, 0x15, 0x4f, 0x82, 0xb4, 0x17, 0x3f, 0x69, 0xf0, 0xee,
0x8d, 0xd4, 0x39, 0xff, 0xf3, 0x14, 0xcd, 0xbe, 0xc0, 0xe7, 0xf5, 0xb9, 0x37, 0x6a, 0xc7, 0x76,
0x45, 0x86, 0x4f, 0xf2, 0x0c, 0x45, 0x24, 0x3b, 0xb2, 0x33, 0x11, 0xaf, 0x8e, 0x05, 0x5d, 0xa6,
0x9c, 0xe5, 0x8e, 0x2c, 0x61, 0x0f, 0x22, 0xf1, 0x62, 0x56, 0x17, 0x20, 0xea, 0xc3, 0x9d, 0x33,
0x1a, 0xba, 0x7e, 0x78, 0x91, 0x02, 0x7c, 0x1f, 0xf6, 0xd6, 0x38, 0x3c, 0x9e, 0x39, 0x0e, 0x4d,
0x12, 0x05, 0xd6, 0xd0, 0x16, 0xf4, 0x9e, 0x12, 0x3f, 0xa0, 0xae, 0x82, 0x36, 0x90, 0x09, 0x5b,
0xdf, 0xc9, 0x7f, 0x52, 0x4a, 0x12, 0xfd, 0xa0, 0x0b, 0x50, 0xfc, 0xa7, 0x74, 0xde, 0x16, 0xff,
0x15, 0x1d, 0xfe, 0x15, 0x00, 0x00, 0xff, 0xff, 0xb7, 0x6a, 0xa5, 0xfa, 0x68, 0x12, 0x00, 0x00,
0x14, 0x35, 0x45, 0x49, 0x0e, 0xaf, 0x64, 0x5b, 0x99, 0x44, 0x2e, 0x61, 0xb8, 0x89, 0x40, 0xf4,
0x61, 0xa4, 0xad, 0x51, 0xd8, 0xe9, 0x23, 0x9b, 0x34, 0xb6, 0xac, 0xd4, 0x01, 0x9a, 0xc6, 0x1d,
0x31, 0x45, 0x0b, 0x64, 0x33, 0x26, 0x27, 0x26, 0x51, 0x8a, 0x14, 0xc8, 0x91, 0x2d, 0x2d, 0xbb,
0xed, 0xaa, 0xbf, 0xd2, 0x2e, 0xbb, 0xe8, 0x6f, 0x64, 0xd9, 0x5f, 0x29, 0x66, 0x38, 0x24, 0x87,
0x14, 0xad, 0x04, 0x41, 0x17, 0x2d, 0xd0, 0xe5, 0x9c, 0xfb, 0x3a, 0xf7, 0xc1, 0x3b, 0x23, 0x41,
0x6f, 0x7e, 0x40, 0x99, 0x47, 0x63, 0x3a, 0x9b, 0xec, 0x4f, 0xe3, 0x88, 0x45, 0xa8, 0xc5, 0x16,
0x53, 0x9a, 0xec, 0xdc, 0x64, 0x31, 0x09, 0x13, 0xe2, 0x30, 0x3f, 0x0a, 0x53, 0xc9, 0xce, 0x06,
0x71, 0x9c, 0x68, 0x16, 0xb2, 0xf4, 0x68, 0xbd, 0x6a, 0x42, 0xef, 0x87, 0xdc, 0xfa, 0x48, 0x68,
0xa2, 0xcf, 0xa1, 0x43, 0x99, 0x77, 0x30, 0xf4, 0x88, 0x1f, 0x1e, 0x1e, 0x9a, 0xda, 0x40, 0xdb,
0xeb, 0x1c, 0xa0, 0x7d, 0xe1, 0x73, 0x7f, 0x54, 0x48, 0x4e, 0xd7, 0xb0, 0xaa, 0xc8, 0xed, 0xae,
0x7c, 0xe6, 0xb9, 0x31, 0xb9, 0x1a, 0x31, 0xcf, 0x6c, 0xac, 0xb2, 0x53, 0x14, 0xd1, 0x57, 0xb0,
0x95, 0x1d, 0xb3, 0x98, 0xba, 0xb0, 0xbd, 0x25, 0x6d, 0x25, 0x6a, 0x47, 0x23, 0xe6, 0x9d, 0xae,
0xe1, 0xaa, 0x36, 0x7a, 0x00, 0x5d, 0x47, 0x51, 0x31, 0x9b, 0xab, 0xac, 0x4b, 0xaa, 0xdc, 0x94,
0xb8, 0xee, 0xf7, 0x24, 0xf0, 0x5d, 0xc2, 0xa2, 0xd8, 0x6c, 0x95, 0x4c, 0x9f, 0x26, 0x17, 0xb9,
0x88, 0x9b, 0xaa, 0xaa, 0x9c, 0x76, 0x4c, 0x27, 0xd1, 0x25, 0x2d, 0xac, 0xdb, 0xab, 0xac, 0xab,
0xda, 0xe8, 0x0b, 0xe8, 0x4c, 0x22, 0xd7, 0x7f, 0xb9, 0x38, 0x8b, 0xae, 0x68, 0x6c, 0xae, 0xaf,
0x32, 0x56, 0x35, 0x91, 0x0d, 0xfd, 0x84, 0xb2, 0x61, 0x14, 0x26, 0x34, 0x4c, 0x66, 0x89, 0xed,
0xc5, 0x34, 0xf1, 0xa2, 0xc0, 0x35, 0x6f, 0x08, 0x17, 0xbb, 0x85, 0x8b, 0x65, 0x9d, 0xd3, 0x35,
0x5c, 0x6f, 0x8c, 0x0e, 0xe1, 0x86, 0x98, 0x97, 0x97, 0x34, 0x36, 0x0d, 0xe1, 0xa8, 0x2f, 0x1d,
0x1d, 0x25, 0x09, 0x65, 0x89, 0x2d, 0x85, 0xa7, 0x6b, 0x38, 0x57, 0x44, 0x9b, 0xd0, 0x60, 0x0b,
0x13, 0x06, 0xda, 0x5e, 0x0b, 0x37, 0xd8, 0xe2, 0x78, 0x1d, 0x5a, 0x97, 0x24, 0x98, 0x51, 0xeb,
0x6b, 0xe8, 0xd7, 0xc6, 0x47, 0xfb, 0x80, 0x9c, 0x65, 0xe6, 0x7c, 0xc8, 0x74, 0x5c, 0x23, 0xb1,
0x1e, 0x42, 0x57, 0xad, 0x05, 0x32, 0x61, 0x9d, 0xb8, 0x6e, 0x4c, 0x93, 0x44, 0x18, 0x19, 0x38,
0x3b, 0xa2, 0xdb, 0xd0, 0x9a, 0x8a, 0x4a, 0x36, 0x84, 0xb3, 0xf4, 0x60, 0xbd, 0xd2, 0xa1, 0xa3,
0x0c, 0x1f, 0xda, 0x83, 0xad, 0x91, 0x9c, 0x77, 0x01, 0x3d, 0x39, 0x91, 0xc1, 0xab, 0x30, 0xba,
0x0f, 0xfd, 0xe3, 0xd8, 0x77, 0x2f, 0xe8, 0x30, 0x0a, 0x59, 0x4c, 0x1c, 0x76, 0x24, 0xe3, 0x36,
0x44, 0xdc, 0x7a, 0x21, 0x67, 0xf1, 0x6d, 0x14, 0x3a, 0x54, 0xcc, 0xb0, 0x8e, 0xd3, 0x03, 0x8f,
0x1a, 0x44, 0x0e, 0x09, 0x86, 0x91, 0x1f, 0x8e, 0x17, 0x93, 0xf3, 0x28, 0x10, 0x53, 0x6a, 0xe0,
0x2a, 0x8c, 0xde, 0x83, 0x8d, 0x1c, 0x1a, 0xcd, 0xa9, 0x23, 0x46, 0xd2, 0xc0, 0x65, 0x10, 0x1d,
0xc0, 0x6d, 0x3b, 0xfa, 0x89, 0x86, 0x55, 0x6a, 0x6d, 0xa1, 0x5c, 0x2b, 0x43, 0x1f, 0xc0, 0x66,
0x96, 0xe2, 0x98, 0x86, 0xae, 0x1c, 0x39, 0x03, 0x57, 0x50, 0xce, 0x55, 0x16, 0x0b, 0x53, 0x87,
0xfa, 0x97, 0x34, 0x16, 0x83, 0x65, 0xe0, 0x2a, 0x8c, 0xee, 0x41, 0x2f, 0x6f, 0x4c, 0xc6, 0xc0,
0x10, 0xaa, 0x4b, 0x38, 0xda, 0x86, 0xf6, 0xd1, 0x84, 0xaf, 0x1e, 0x31, 0x2d, 0x06, 0x96, 0x27,
0xb4, 0x0b, 0xc6, 0x30, 0x20, 0xfe, 0xc4, 0x5e, 0x4c, 0xa9, 0xd9, 0x11, 0x35, 0x2b, 0x00, 0xb4,
0x03, 0x37, 0x4e, 0xa8, 0xe3, 0x4f, 0x48, 0x90, 0x98, 0x5d, 0x21, 0xcc, 0xcf, 0xd6, 0xaf, 0x1a,
0xa0, 0x67, 0x31, 0x71, 0x02, 0x2a, 0xf4, 0x79, 0xba, 0x34, 0x64, 0x75, 0xf4, 0xb5, 0x7a, 0xfa,
0x05, 0xa5, 0xc6, 0xf5, 0x94, 0xf4, 0x55, 0x94, 0x9a, 0x15, 0x4a, 0xbf, 0x34, 0xa0, 0xab, 0xee,
0x1b, 0xde, 0xcd, 0x52, 0x2f, 0x24, 0x95, 0x32, 0xc8, 0xb5, 0xa4, 0x95, 0x6c, 0x4c, 0xca, 0xa7,
0x0c, 0xf2, 0x6a, 0x67, 0x9d, 0xca, 0x33, 0xd3, 0xd3, 0x6a, 0x57, 0x71, 0x25, 0xb5, 0x66, 0x29,
0xb5, 0x9a, 0x39, 0x6c, 0xbd, 0xe1, 0x1c, 0xb6, 0xeb, 0xe6, 0x50, 0x2d, 0xc6, 0x7a, 0xa5, 0x18,
0xbf, 0x37, 0x01, 0x09, 0x42, 0x53, 0xf6, 0xff, 0x07, 0xf8, 0x5f, 0xfd, 0x00, 0x4d, 0x58, 0x9f,
0xdb, 0xf3, 0x53, 0x92, 0x78, 0xe2, 0xfb, 0xeb, 0xe2, 0xec, 0x28, 0x24, 0xa7, 0xd4, 0xbf, 0xf0,
0x98, 0xb9, 0x31, 0xd0, 0xf6, 0x9a, 0x38, 0x3b, 0xa2, 0x3b, 0x00, 0x67, 0x71, 0x34, 0xf5, 0xa8,
0xb3, 0x78, 0x72, 0x62, 0x6e, 0x8a, 0x68, 0x0a, 0x52, 0x1a, 0x9a, 0xad, 0xca, 0xd0, 0xfc, 0xa5,
0xc1, 0x2d, 0x39, 0x34, 0xff, 0xea, 0x0f, 0x69, 0x17, 0x8c, 0x11, 0xf3, 0x4a, 0x9f, 0x50, 0x01,
0x94, 0x32, 0x6c, 0x57, 0x32, 0xbc, 0x84, 0x9e, 0x4c, 0xf0, 0xad, 0x2f, 0x35, 0xb5, 0x2b, 0xfa,
0xb5, 0x5d, 0x69, 0x96, 0xba, 0x62, 0xfd, 0xa9, 0xc1, 0xae, 0x0c, 0x3c, 0xae, 0x7d, 0x00, 0xdc,
0x87, 0xfe, 0x34, 0xa6, 0xc3, 0xeb, 0x2e, 0xe7, 0x7a, 0x21, 0xb7, 0x0a, 0xa3, 0xab, 0x1a, 0xab,
0x94, 0x70, 0xbd, 0xf0, 0xad, 0x12, 0xd8, 0x83, 0xed, 0xef, 0x66, 0x34, 0x5e, 0x8c, 0x98, 0x97,
0x0d, 0xd3, 0x19, 0x89, 0xc9, 0x24, 0xe1, 0xaf, 0x10, 0xb9, 0x45, 0x0c, 0xdc, 0x78, 0x72, 0x62,
0xbd, 0xd2, 0xd4, 0xcd, 0x93, 0x29, 0x57, 0xd5, 0xd0, 0x27, 0xd0, 0x1e, 0x33, 0xc2, 0x66, 0x89,
0x7c, 0xab, 0x66, 0xef, 0x9d, 0xcc, 0x20, 0x15, 0x62, 0xa9, 0x84, 0x1e, 0xc1, 0x96, 0xf8, 0x2e,
0xf2, 0xb6, 0x25, 0xa6, 0x3e, 0xd0, 0xf7, 0x3a, 0x07, 0xdb, 0xd9, 0x4b, 0xb3, 0x2c, 0xc5, 0x55,
0x75, 0xee, 0x21, 0x3f, 0x09, 0x19, 0xbf, 0x41, 0x54, 0x0f, 0x15, 0x29, 0xae, 0xaa, 0x5b, 0x3f,
0x2e, 0x71, 0xe0, 0x13, 0xe2, 0x70, 0x48, 0x26, 0x96, 0x1e, 0xd0, 0xa7, 0x00, 0x97, 0x05, 0xcf,
0x34, 0xbf, 0x9e, 0x8c, 0x32, 0x66, 0xb1, 0x1f, 0x5e, 0x3c, 0x25, 0x53, 0xac, 0xe8, 0x58, 0xa3,
0x25, 0x72, 0x7c, 0xc8, 0x73, 0x05, 0xe9, 0xbe, 0x00, 0x8a, 0xc0, 0x0d, 0x25, 0xb0, 0xf5, 0x11,
0x18, 0xb9, 0x7f, 0xbe, 0x09, 0x14, 0x16, 0xda, 0x40, 0xe7, 0x9b, 0x40, 0x89, 0x79, 0x02, 0x1b,
0x79, 0xcc, 0x6f, 0xfc, 0x84, 0xa1, 0xc3, 0x25, 0x83, 0xfa, 0x27, 0x71, 0xc9, 0xcb, 0x0b, 0xd8,
0x2c, 0xb7, 0x0c, 0xdd, 0x83, 0xa6, 0x4d, 0xe7, 0xe9, 0x92, 0xd8, 0xcc, 0xab, 0x3b, 0x62, 0x5e,
0x7a, 0x65, 0xc8, 0xc6, 0x0a, 0x1d, 0xce, 0xf1, 0xb1, 0x1f, 0x92, 0x60, 0xa8, 0xe4, 0xa2, 0x20,
0xd6, 0x67, 0xd0, 0x17, 0x63, 0x57, 0x94, 0x5c, 0x4e, 0xdd, 0xca, 0xea, 0x58, 0x01, 0xf4, 0xe5,
0x08, 0x96, 0xad, 0xdf, 0x2a, 0x45, 0x4e, 0x92, 0x45, 0x8c, 0x04, 0x67, 0xca, 0x2e, 0x50, 0x10,
0xeb, 0x1d, 0x49, 0xd2, 0xce, 0xa1, 0x94, 0xa4, 0xf5, 0x25, 0x6c, 0xab, 0x34, 0x0a, 0x79, 0xc5,
0xa5, 0xb6, 0xe4, 0xf2, 0x2e, 0xbc, 0x2b, 0x4c, 0x96, 0xbf, 0x5e, 0xe9, 0xfa, 0x0c, 0xee, 0xa8,
0xae, 0xff, 0x81, 0xb7, 0xfe, 0x6f, 0x1a, 0xdc, 0x15, 0xbe, 0xd2, 0x35, 0x9a, 0xfe, 0xee, 0x38,
0x5e, 0xd8, 0x73, 0x7e, 0x15, 0xc9, 0xaa, 0x0f, 0xa0, 0xc3, 0xf8, 0xce, 0x97, 0xab, 0x37, 0xad,
0xbb, 0x0a, 0xf1, 0xbe, 0xb8, 0x7e, 0x4c, 0xc5, 0x8f, 0x59, 0x59, 0xaa, 0x02, 0xe0, 0x0b, 0x9d,
0xcd, 0xf3, 0x97, 0x9d, 0x81, 0xe5, 0x89, 0x5b, 0x09, 0x27, 0xfc, 0xba, 0x94, 0xbb, 0xbe, 0x00,
0xf8, 0x56, 0x72, 0xd3, 0x05, 0x2e, 0x96, 0xbd, 0x8e, 0xb3, 0xa3, 0xf5, 0x1c, 0x4c, 0xb5, 0x0a,
0x2a, 0x73, 0xf4, 0x00, 0xf4, 0x98, 0x66, 0x3d, 0xfe, 0x50, 0xf6, 0xf8, 0x3a, 0xed, 0x2c, 0x4f,
0xcc, 0x6d, 0xac, 0x3f, 0x34, 0x18, 0xbc, 0x4e, 0xf3, 0x0d, 0x6a, 0x21, 0x34, 0x18, 0x09, 0x4a,
0xef, 0x5c, 0x15, 0x5a, 0x55, 0x8f, 0xa2, 0x8a, 0xcd, 0x6a, 0x15, 0x4b, 0xd5, 0x6a, 0x55, 0xaa,
0x65, 0x45, 0x70, 0x4b, 0x90, 0xc6, 0x34, 0x20, 0x0b, 0x1a, 0x1f, 0x93, 0x80, 0xf0, 0x37, 0xd8,
0xeb, 0xe9, 0x2a, 0xf7, 0x60, 0xa3, 0x7c, 0x0f, 0x96, 0x02, 0xea, 0xd5, 0x80, 0x2f, 0x60, 0x47,
0x2d, 0x56, 0x25, 0xee, 0x43, 0xb5, 0x0d, 0x1f, 0xd7, 0xb4, 0xa1, 0xac, 0xff, 0x38, 0x8a, 0x9f,
0x85, 0x54, 0x3c, 0x2c, 0xd2, 0x5e, 0xfc, 0xac, 0xc1, 0xfb, 0x6f, 0xa4, 0xce, 0xf9, 0x9f, 0xa7,
0x68, 0x76, 0x8f, 0x9f, 0xd7, 0xe7, 0xde, 0xa8, 0x1d, 0xdb, 0x15, 0x19, 0x3e, 0xca, 0x33, 0x14,
0x91, 0xec, 0xc8, 0xce, 0x44, 0xbc, 0x3a, 0x16, 0x74, 0x99, 0x72, 0x96, 0x9b, 0xb6, 0x84, 0xdd,
0x7b, 0x2e, 0xde, 0xdd, 0xea, 0x02, 0x44, 0x7d, 0xb8, 0x79, 0x46, 0x43, 0xd7, 0x0f, 0x2f, 0x52,
0x80, 0xef, 0xc3, 0xde, 0x1a, 0x87, 0xc7, 0x33, 0xc7, 0xa1, 0x49, 0xa2, 0xc0, 0x1a, 0xba, 0x0d,
0xbd, 0xc7, 0xc4, 0x0f, 0xa8, 0xab, 0xa0, 0x8d, 0x83, 0x2e, 0x40, 0xf1, 0xff, 0xd3, 0x79, 0x5b,
0xfc, 0xaf, 0x74, 0xf8, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1f, 0xcd, 0x0e, 0x4f, 0x94, 0x12,
0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
......
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