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 }