github.com/codingfuture/orig-energi3@v0.8.4/energi/consensus/blacklist.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  	"github.com/ethereum/go-ethereum/common"
    21  	"github.com/ethereum/go-ethereum/core"
    22  	"github.com/ethereum/go-ethereum/core/state"
    23  	"github.com/ethereum/go-ethereum/core/types"
    24  	"github.com/ethereum/go-ethereum/log"
    25  
    26  	energi_params "energi.world/core/gen3/energi/params"
    27  )
    28  
    29  var (
    30  	blacklistValue = common.BytesToHash([]byte{0x01})
    31  )
    32  
    33  func (e *Energi) processBlacklists(
    34  	chain ChainReader,
    35  	header *types.Header,
    36  	statedb *state.StateDB,
    37  ) (err error) {
    38  	blregistry := energi_params.Energi_BlacklistRegistry
    39  
    40  	enumerateData, err := e.blacklistAbi.Pack("enumerateBlocked")
    41  	if err != nil {
    42  		log.Error("Fail to prepare enumerateBlocked() call", "err", err)
    43  		return err
    44  	}
    45  
    46  	msg := types.NewMessage(
    47  		blregistry,
    48  		&blregistry,
    49  		0,
    50  		common.Big0,
    51  		e.unlimitedGas,
    52  		common.Big0,
    53  		enumerateData,
    54  		false,
    55  	)
    56  	rev_id := statedb.Snapshot()
    57  	evm := e.createEVM(msg, chain, header, statedb)
    58  	gp := core.GasPool(e.unlimitedGas)
    59  	output, gas_used, _, err := core.ApplyMessage(evm, msg, &gp)
    60  	statedb.RevertToSnapshot(rev_id)
    61  	if err != nil {
    62  		log.Error("Failed in enumerateBlocked() call", "err", err)
    63  		return err
    64  	}
    65  
    66  	if gas_used > e.callGas {
    67  		log.Warn("BlacklistRegistry::enumerateDrainable() took excessive gas",
    68  			"gas", gas_used, "limit", e.callGas)
    69  	}
    70  
    71  	address_list := new([]common.Address)
    72  	err = e.blacklistAbi.Unpack(&address_list, "enumerateBlocked", output)
    73  	if err != nil {
    74  		log.Error("Failed to unpack enumerateBlocked() call", "err", err)
    75  		return err
    76  	}
    77  
    78  	log.Debug("Address blacklist", "address_list", address_list)
    79  	empty_addr := common.Address{}
    80  	state_obj := statedb.GetOrNewStateObject(energi_params.Energi_Blacklist)
    81  	db := statedb.Database()
    82  	keep := make(state.KeepStorage, len(*address_list))
    83  	whitelist := e.createWhitelist(statedb)
    84  
    85  	for _, addr := range *address_list {
    86  		if addr != empty_addr && !whitelist[addr] {
    87  			addr_hash := addr.Hash()
    88  
    89  			if (state_obj.GetState(db, addr_hash) == common.Hash{}) {
    90  				log.Debug("New blacklisted account", "addr", addr)
    91  			}
    92  
    93  			log.Trace("Blacklisting account", "addr", addr)
    94  			state_obj.SetState(db, addr_hash, blacklistValue)
    95  			keep[addr_hash] = true
    96  		}
    97  	}
    98  
    99  	state_obj.CleanupStorage(keep)
   100  
   101  	//
   102  	wl_state_obj := statedb.GetOrNewStateObject(energi_params.Energi_Whitelist)
   103  	wl_keep := make(state.KeepStorage, len(whitelist))
   104  	for addr := range whitelist {
   105  		addr_hash := addr.Hash()
   106  
   107  		if (wl_state_obj.GetState(db, addr_hash) == common.Hash{}) {
   108  			log.Debug("New whitelisted account", "addr", addr)
   109  		}
   110  
   111  		log.Trace("Whitelisting account", "addr", addr)
   112  		wl_state_obj.SetState(db, addr_hash, blacklistValue)
   113  		wl_keep[addr_hash] = true
   114  	}
   115  
   116  	wl_state_obj.CleanupStorage(wl_keep)
   117  
   118  	return nil
   119  }
   120  
   121  var (
   122  	consensusProxies = []common.Address{
   123  		energi_params.Energi_Treasury,
   124  		energi_params.Energi_MasternodeRegistry,
   125  		energi_params.Energi_StakerReward,
   126  		energi_params.Energi_BackboneReward,
   127  		energi_params.Energi_SporkRegistry,
   128  		energi_params.Energi_CheckpointRegistry,
   129  		energi_params.Energi_BlacklistRegistry,
   130  		energi_params.Energi_MasternodeToken,
   131  	}
   132  
   133  	consensusStandalone = []common.Address{
   134  		energi_params.Energi_MigrationContract,
   135  		energi_params.Energi_SystemFaucet,
   136  	}
   137  )
   138  
   139  func (e *Energi) createWhitelist(
   140  	statedb *state.StateDB,
   141  ) map[common.Address]bool {
   142  	whitelist := map[common.Address]bool{}
   143  
   144  	for _, addr := range consensusProxies {
   145  		whitelist[addr] = true
   146  		impl := statedb.GetState(addr, energi_params.Storage_ProxyImpl)
   147  		whitelist[common.BytesToAddress(impl[:])] = true
   148  	}
   149  
   150  	for _, addr := range consensusStandalone {
   151  		whitelist[addr] = true
   152  	}
   153  
   154  	return whitelist
   155  }
   156  
   157  func (e *Energi) processDrainable(
   158  	chain ChainReader,
   159  	header *types.Header,
   160  	statedb *state.StateDB,
   161  	txs types.Transactions,
   162  	receipts types.Receipts,
   163  ) (types.Transactions, types.Receipts, error) {
   164  	blregistry := energi_params.Energi_BlacklistRegistry
   165  	var comp_fund common.Address
   166  
   167  	txhash := common.Hash{}
   168  	bhash := header.Hash()
   169  	statedb.Prepare(txhash, bhash, len(txs))
   170  
   171  	// 1. List drainable addresses address
   172  	//---
   173  	enumerateData, err := e.blacklistAbi.Pack("enumerateDrainable")
   174  	if err != nil {
   175  		log.Error("Fail to prepare enumerateDrainable() call", "err", err)
   176  		return nil, nil, err
   177  	}
   178  
   179  	msg := types.NewMessage(
   180  		blregistry,
   181  		&blregistry,
   182  		0,
   183  		common.Big0,
   184  		e.unlimitedGas,
   185  		common.Big0,
   186  		enumerateData,
   187  		false,
   188  	)
   189  	rev_id := statedb.Snapshot()
   190  	evm := e.createEVM(msg, chain, header, statedb)
   191  	gp := core.GasPool(e.unlimitedGas)
   192  	output, gas_used, _, err := core.ApplyMessage(evm, msg, &gp)
   193  	statedb.RevertToSnapshot(rev_id)
   194  	if err != nil {
   195  		log.Error("Failed in enumerateDrainable() call", "err", err)
   196  		return nil, nil, err
   197  	}
   198  
   199  	if gas_used > e.callGas {
   200  		log.Warn("BlacklistRegistry::enumerateDrainable() took excessive gas",
   201  			"gas", gas_used, "limit", e.callGas)
   202  	}
   203  
   204  	address_list := new([]common.Address)
   205  	err = e.blacklistAbi.Unpack(&address_list, "enumerateDrainable", output)
   206  	if err != nil {
   207  		log.Error("Failed to unpack enumerateDrainable() call", "err", err)
   208  		return nil, nil, err
   209  	}
   210  
   211  	log.Debug("Address drain list", "address_list", address_list)
   212  
   213  	// 2. Get current compensation fund address
   214  	if len(*address_list) > 0 {
   215  		enumerateData, err := e.blacklistAbi.Pack("compensation_fund")
   216  		if err != nil {
   217  			log.Error("Fail to prepare compensation_fund() call", "err", err)
   218  			return nil, nil, err
   219  		}
   220  
   221  		msg := types.NewMessage(
   222  			blregistry,
   223  			&blregistry,
   224  			0,
   225  			common.Big0,
   226  			e.callGas,
   227  			common.Big0,
   228  			enumerateData,
   229  			false,
   230  		)
   231  		rev_id := statedb.Snapshot()
   232  		evm := e.createEVM(msg, chain, header, statedb)
   233  		gp = core.GasPool(e.callGas)
   234  		output, _, _, err := core.ApplyMessage(evm, msg, &gp)
   235  		statedb.RevertToSnapshot(rev_id)
   236  		if err != nil {
   237  			log.Error("Failed in compensation_fund() call", "err", err)
   238  			return nil, nil, err
   239  		}
   240  
   241  		err = e.blacklistAbi.Unpack(&comp_fund, "compensation_fund", output)
   242  		if err != nil {
   243  			log.Error("Failed to unpack compensation_fund() call", "err", err)
   244  			return nil, nil, err
   245  		}
   246  	}
   247  
   248  	// 3. Drain
   249  	//---
   250  	empty_addr := common.Address{}
   251  
   252  	for _, addr := range *address_list {
   253  		if addr == empty_addr {
   254  			continue
   255  		}
   256  
   257  		//--
   258  		bal := statedb.GetBalance(addr)
   259  
   260  		// Skip, if nothing
   261  		if bal.Cmp(common.Big0) == 0 {
   262  			continue
   263  		}
   264  
   265  		// Skip whitelisted
   266  		if core.CanTransfer(statedb, addr, bal) {
   267  			continue
   268  		}
   269  
   270  		log.Trace("Draining account", "fund", comp_fund, "addr", addr, "bal", bal)
   271  
   272  		//====================================
   273  		contributeData, err := e.treasuryAbi.Pack("contribute")
   274  		if err != nil {
   275  			log.Error("Fail to prepare contribute() call", "err", err)
   276  			return nil, nil, err
   277  		}
   278  
   279  		tx := types.NewTransaction(
   280  			statedb.GetNonce(addr),
   281  			comp_fund,
   282  			bal,
   283  			e.xferGas,
   284  			common.Big0,
   285  			contributeData)
   286  		tx = tx.WithConsensusSender(addr)
   287  
   288  		statedb.Prepare(tx.Hash(), bhash, len(txs))
   289  
   290  		msg, err = tx.AsMessage(&ConsensusSigner{})
   291  		if err != nil {
   292  			log.Error("Failed in onDrain() msg", "err", err)
   293  			return nil, nil, err
   294  		}
   295  
   296  		statedb.SetState(energi_params.Energi_Blacklist, addr.Hash(), common.Hash{})
   297  		evm = e.createEVM(msg, chain, header, statedb)
   298  		gp = core.GasPool(msg.Gas())
   299  		_, gas1, failed, err := core.ApplyMessage(evm, msg, &gp)
   300  		statedb.SetState(energi_params.Energi_Blacklist, addr.Hash(), blacklistValue)
   301  
   302  		if err != nil {
   303  			log.Error("Failed in onDrain() call", "err", err)
   304  			return nil, nil, err
   305  		}
   306  
   307  		root := statedb.IntermediateRoot(chain.Config().IsEIP158(header.Number))
   308  		receipt := types.NewReceipt(root.Bytes(), failed, header.GasUsed)
   309  		receipt.TxHash = tx.Hash()
   310  		receipt.GasUsed = gas1
   311  		receipt.Logs = statedb.GetLogs(tx.Hash())
   312  		receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
   313  
   314  		txs = append(txs, tx)
   315  		receipts = append(receipts, receipt)
   316  
   317  		//====================================
   318  		collectData, err := e.blacklistAbi.Pack("onDrain", addr)
   319  		if err != nil {
   320  			log.Error("Fail to prepare onDrain() call", "err", err, "addr", addr)
   321  			return nil, nil, err
   322  		}
   323  
   324  		tx = types.NewTransaction(
   325  			statedb.GetNonce(blregistry),
   326  			blregistry,
   327  			common.Big0,
   328  			e.xferGas,
   329  			common.Big0,
   330  			collectData)
   331  		tx = tx.WithConsensusSender(blregistry)
   332  
   333  		statedb.Prepare(tx.Hash(), bhash, len(txs))
   334  
   335  		msg, err = tx.AsMessage(&ConsensusSigner{})
   336  		if err != nil {
   337  			log.Error("Failed in onDrain() msg", "err", err)
   338  			return nil, nil, err
   339  		}
   340  
   341  		evm = e.createEVM(msg, chain, header, statedb)
   342  		gp = core.GasPool(msg.Gas())
   343  		_, gas2, failed, err := core.ApplyMessage(evm, msg, &gp)
   344  		if err != nil {
   345  			log.Error("Failed in onDrain() call", "err", err)
   346  			return nil, nil, err
   347  		}
   348  
   349  		root = statedb.IntermediateRoot(chain.Config().IsEIP158(header.Number))
   350  		receipt = types.NewReceipt(root.Bytes(), failed, header.GasUsed)
   351  		receipt.TxHash = tx.Hash()
   352  		receipt.GasUsed = gas2
   353  		receipt.Logs = statedb.GetLogs(tx.Hash())
   354  		receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
   355  
   356  		txs = append(txs, tx)
   357  		receipts = append(receipts, receipt)
   358  	}
   359  
   360  	return txs, receipts, nil
   361  }