github.com/codingfuture/orig-energi3@v0.8.4/energi/consensus/migration.go (about)

     1  // Copyright 2019 The Energi Core Authors
     2  // This file is part of the Energi Core library.
     3  //
     4  // The Energi Core library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The Energi Core library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the Energi Core library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package consensus
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"io"
    23  	"math/big"
    24  	"os"
    25  	"strings"
    26  
    27  	"github.com/ethereum/go-ethereum/accounts/abi"
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/consensus"
    30  	"github.com/ethereum/go-ethereum/core"
    31  	"github.com/ethereum/go-ethereum/core/state"
    32  	"github.com/ethereum/go-ethereum/core/types"
    33  	"github.com/ethereum/go-ethereum/log"
    34  	"github.com/ethereum/go-ethereum/params"
    35  	"github.com/ethereum/go-ethereum/rlp"
    36  
    37  	"github.com/shengdoushi/base58"
    38  
    39  	energi_abi "energi.world/core/gen3/energi/abi"
    40  	energi_params "energi.world/core/gen3/energi/params"
    41  )
    42  
    43  const (
    44  	gasPerMigrationEntry uint64 = 100000
    45  )
    46  
    47  func (e *Energi) finalizeMigration(
    48  	chain ChainReader,
    49  	header *types.Header,
    50  	statedb *state.StateDB,
    51  	txs types.Transactions,
    52  ) error {
    53  	if !header.IsGen2Migration() {
    54  		return nil
    55  	}
    56  
    57  	// One migration and one block reward
    58  	if len(txs) != 2 {
    59  		err := errors.New("Wrong number of migration block txs")
    60  		log.Error("Failed to finalize migration", "err", err)
    61  		return err
    62  	}
    63  
    64  	migration_abi, err := abi.JSON(strings.NewReader(energi_abi.Gen2MigrationABI))
    65  	if err != nil {
    66  		return err
    67  	}
    68  
    69  	callData, err := migration_abi.Pack("totalAmount")
    70  	if err != nil {
    71  		log.Error("Failed to prepare totalAmount() call", "err", err)
    72  		return err
    73  	}
    74  
    75  	// totalAmount()
    76  	msg := types.NewMessage(
    77  		e.systemFaucet,
    78  		&energi_params.Energi_MigrationContract,
    79  		0,
    80  		common.Big0,
    81  		e.callGas,
    82  		common.Big0,
    83  		callData,
    84  		false,
    85  	)
    86  	rev_id := statedb.Snapshot()
    87  	evm := e.createEVM(msg, chain, header, statedb)
    88  	gp := core.GasPool(e.callGas)
    89  	output, _, _, err := core.ApplyMessage(evm, msg, &gp)
    90  	statedb.RevertToSnapshot(rev_id)
    91  	if err != nil {
    92  		log.Error("Failed in totalAmount() call", "err", err)
    93  		return err
    94  	}
    95  
    96  	//
    97  	totalAmount := big.NewInt(0)
    98  	err = migration_abi.Unpack(&totalAmount, "totalAmount", output)
    99  	if err != nil {
   100  		log.Error("Failed to unpack totalAmount() call", "err", err)
   101  		return err
   102  	}
   103  
   104  	statedb.SetBalance(energi_params.Energi_MigrationContract, totalAmount)
   105  	log.Warn("Setting Migration contract balance", "amount", totalAmount)
   106  
   107  	return nil
   108  }
   109  
   110  func MigrationTx(
   111  	signer types.Signer,
   112  	header *types.Header,
   113  	migration_file string,
   114  	engine consensus.Engine,
   115  ) (res *types.Transaction) {
   116  	file, err := os.Open(migration_file)
   117  	if err != nil {
   118  		log.Error("Failed to open snapshot", "err", err)
   119  		return nil
   120  	}
   121  	defer file.Close()
   122  
   123  	snapshot, err := parseSnapshot(file)
   124  	if err != nil {
   125  		log.Error("Failed to parse snapshot", "err", err)
   126  		return nil
   127  	}
   128  
   129  	return migrationTx(signer, header, snapshot, engine)
   130  }
   131  
   132  func migrationTx(
   133  	signer types.Signer,
   134  	header *types.Header,
   135  	snapshot *snapshot,
   136  	engine consensus.Engine,
   137  ) (res *types.Transaction) {
   138  	e, ok := engine.(*Energi)
   139  	if !ok {
   140  		log.Error("Not Energi consensus engine")
   141  		return nil
   142  	}
   143  
   144  	owners, amounts, blacklist := createSnapshotParams(snapshot)
   145  	if owners == nil || amounts == nil || blacklist == nil {
   146  		log.Error("Failed to create arguments")
   147  		return nil
   148  	}
   149  
   150  	migration_abi, err := abi.JSON(strings.NewReader(energi_abi.Gen2MigrationABI))
   151  	if err != nil {
   152  		panic(err)
   153  	}
   154  
   155  	callData, err := migration_abi.Pack("setSnapshot", owners, amounts, blacklist)
   156  	if err != nil {
   157  		panic(err)
   158  	}
   159  
   160  	gasLimit := gasPerMigrationEntry * uint64(len(owners))
   161  	header.GasLimit = gasLimit
   162  	header.Extra, err = rlp.EncodeToBytes([]interface{}{
   163  		uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch),
   164  		"energi3",
   165  		snapshot.Hash,
   166  	})
   167  	if err != nil {
   168  		panic(err)
   169  	}
   170  
   171  	res = types.NewTransaction(
   172  		uint64(0), // it should be the first transaction
   173  		energi_params.Energi_MigrationContract,
   174  		common.Big0,
   175  		gasLimit,
   176  		common.Big0,
   177  		callData,
   178  	)
   179  
   180  	if e.signerFn == nil {
   181  		log.Error("Signer is not set")
   182  		return nil
   183  	}
   184  
   185  	if e.config == nil {
   186  		log.Error("Engine config is not set")
   187  		return nil
   188  	}
   189  
   190  	tx_hash := signer.Hash(res)
   191  	tx_sig, err := e.signerFn(e.config.MigrationSigner, tx_hash.Bytes())
   192  	if err != nil {
   193  		log.Error("Failed to sign migration tx")
   194  		return nil
   195  	}
   196  
   197  	res, err = res.WithSignature(signer, tx_sig)
   198  	if err != nil {
   199  		log.Error("Failed to pack migration tx")
   200  		return nil
   201  	}
   202  	return
   203  }
   204  
   205  func createSnapshotParams(ss *snapshot) (
   206  	owners []common.Address,
   207  	amounts []*big.Int,
   208  	blacklist []common.Address,
   209  ) {
   210  	owners = make([]common.Address, len(ss.Txouts))
   211  	amounts = make([]*big.Int, len(ss.Txouts))
   212  	blacklist = make([]common.Address, len(ss.Blacklist))
   213  
   214  	// NOTE: Gen 2 precision is 8, but Gen 3 is 18
   215  	multiplier := big.NewInt(1e10)
   216  
   217  	for i, info := range ss.Txouts {
   218  		owner, err := base58.Decode(info.Owner, base58.BitcoinAlphabet)
   219  
   220  		if err != nil {
   221  			log.Error("Failed to decode address", "err", err, "address", info.Owner)
   222  			return nil, nil, nil
   223  		}
   224  
   225  		owner = owner[1 : len(owner)-4]
   226  		owners[i] = common.BytesToAddress(owner)
   227  		amounts[i] = new(big.Int).Mul(info.Amount, multiplier)
   228  	}
   229  
   230  	for i, blo := range ss.Blacklist {
   231  		owner, err := base58.Decode(blo, base58.BitcoinAlphabet)
   232  
   233  		if err != nil {
   234  			log.Error("Failed to decode address", "err", err, "address", blo)
   235  			return nil, nil, nil
   236  		}
   237  
   238  		owner = owner[1 : len(owner)-4]
   239  		blacklist[i] = common.BytesToAddress(owner)
   240  	}
   241  
   242  	return
   243  }
   244  
   245  func parseSnapshot(reader io.Reader) (*snapshot, error) {
   246  	dec := json.NewDecoder(reader)
   247  	dec.DisallowUnknownFields()
   248  	ret := &snapshot{}
   249  	err := dec.Decode(ret)
   250  	return ret, err
   251  }
   252  
   253  type snapshotItem struct {
   254  	Owner  string   `json:"owner"`
   255  	Amount *big.Int `json:"amount"`
   256  	Atype  string   `json:"type"`
   257  }
   258  
   259  type snapshot struct {
   260  	Txouts    []snapshotItem `json:"snapshot_utxos"`
   261  	Blacklist []string       `json:"snapshot_blacklist"`
   262  	Hash      string         `json:"snapshot_hash"`
   263  }