diff --git a/common/constants.go b/common/constants.go index 781cc05d6c..4ebee31c45 100644 --- a/common/constants.go +++ b/common/constants.go @@ -22,7 +22,8 @@ const ( ) var TIP2019Block = big.NewInt(1050000) -var IsTestnet = false +var TIPEVMSignerBlock = big.NewInt(2500000) +var IsTestnet bool = false var StoreRewardFolder string var RollbackHash Hash var MinGasPrice int64 \ No newline at end of file diff --git a/core/blockchain.go b/core/blockchain.go index 90e9a0c0a7..041b9287e7 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1,3 +1,4 @@ + // Copyright 2014 The go-ethereum Authors // This file is part of the go-ethereum library. // @@ -507,7 +508,7 @@ func (bc *BlockChain) insert(block *types.Block) { bc.currentBlock.Store(block) // save cache BlockSigners - if bc.chainConfig.XDPoS != nil { + if bc.chainConfig.XDPoS != nil && !bc.chainConfig.IsTIPEVMSigner(block.Number()) { engine := bc.Engine().(*XDPoS.XDPoS) engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash())) } @@ -1019,6 +1020,11 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. if status == CanonStatTy { bc.insert(block) } + // save cache BlockSigners + if bc.chainConfig.XDPoS != nil && bc.chainConfig.IsTIPEVMSigner(block.Number()) { + engine := bc.Engine().(*XDPoS.XDPoS) + engine.CacheSigner(block.Header(), block.Transactions()) + } bc.futureBlocks.Remove(block.Hash()) return status, nil } diff --git a/core/state/statedb.go b/core/state/statedb.go index bd67e789d5..2ae700cd67 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -357,6 +357,14 @@ func (self *StateDB) deleteStateObject(stateObject *stateObject) { self.setError(self.trie.TryDelete(addr[:])) } +// DeleteAddress removes the address from the state trie. +func (self *StateDB) DeleteAddress(addr common.Address) { + stateObject := self.getStateObject(addr) + if stateObject != nil && !stateObject.deleted { + self.deleteStateObject(stateObject) + } +} + // Retrieve a state object given my the address. Returns nil if not found. func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) { // Prefer 'live' objects. diff --git a/core/state_processor.go b/core/state_processor.go index 6ec3fcc6f1..7f6ad40132 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -73,6 +73,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } + if p.config.IsTIPEVMSigner(header.Number) { + statedb.DeleteAddress(common.HexToAddress(common.BlockSigners)) + } InitSignerInTransactions(p.config, header, block.Transactions()) for i, tx := range block.Transactions() { statedb.Prepare(tx.Hash(), block.Hash(), i) @@ -101,6 +104,9 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } + if p.config.IsTIPEVMSigner(header.Number) { + statedb.DeleteAddress(common.HexToAddress(common.BlockSigners)) + } if cBlock.stop { return nil, nil, 0, ErrStopPreparingBlock } @@ -132,6 +138,9 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) { + if tx.To() != nil && tx.To().String() == common.BlockSigners && config.IsTIPEVMSigner(header.Number) { + return ApplySignTransaction(config, statedb, header, tx, usedGas) + } msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) if err != nil { return nil, 0, err @@ -171,6 +180,41 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common return receipt, gas, err } +func ApplySignTransaction(config *params.ChainConfig, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, uint64, error) { + // Update the state with pending changes + var root []byte + if config.IsByzantium(header.Number) { + statedb.Finalise(true) + } else { + root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() + } + from, err := types.Sender(types.MakeSigner(config, header.Number), tx) + if err != nil { + return nil, 0, err + } + nonce := statedb.GetNonce(from) + if nonce < tx.Nonce() { + return nil, 0, ErrNonceTooHigh + } else if nonce > tx.Nonce() { + return nil, 0, ErrNonceTooLow + } + statedb.SetNonce(from, nonce+1) + // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx + // based on the eip phase, we're passing wether the root touch-delete accounts. + receipt := types.NewReceipt(root, false, *usedGas) + receipt.TxHash = tx.Hash() + receipt.GasUsed = 0 + // if the transaction created a contract, store the creation address in the receipt. + // Set the receipt logs and create a bloom for filtering + log := &types.Log{} + log.Address = common.HexToAddress(common.BlockSigners) + log.BlockNumber = header.Number.Uint64() + statedb.AddLog(log) + receipt.Logs = statedb.GetLogs(tx.Hash()) + receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + return receipt, 0, nil +} + func InitSignerInTransactions(config *params.ChainConfig, header *types.Header, txs types.Transactions) { nWorker := runtime.NumCPU() signer := types.MakeSigner(config, header.Number) @@ -195,4 +239,4 @@ func InitSignerInTransactions(config *params.ChainConfig, header *types.Header, }(from, to) } wg.Wait() -} +} \ No newline at end of file diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 04ffa77651..bb62833bdc 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -950,33 +950,40 @@ func (s *PublicBlockChainAPI) rpcOutputBlockSigners(b *types.Block, ctx context. var signers []common.Address var filterSigners []common.Address if b.Number().Int64() > 0 { - curBlockNumber := b.Number().Uint64() - prevBlockNumber := curBlockNumber + (common.MergeSignRange - (curBlockNumber % common.MergeSignRange)) - latestBlockNumber := s.b.CurrentBlock().Number().Uint64() - if prevBlockNumber >= latestBlockNumber || !s.b.ChainConfig().IsTIP2019(b.Number()) { - prevBlockNumber = curBlockNumber + blockNumber := b.Number().Uint64() + signedBlockNumber := blockNumber + (common.MergeSignRange - (blockNumber % common.MergeSignRange)) + latestBlockNumber := s.b.CurrentBlock().Number() + if signedBlockNumber >= latestBlockNumber.Uint64() || !s.b.ChainConfig().IsTIP2019(b.Number()) { + signedBlockNumber = blockNumber } if engine, ok := s.b.GetEngine().(*XDPoS.XDPoS); ok { - prevBlock, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(prevBlockNumber)) - if err != nil { - log.Error("Fail to get previous block", "error", err) - return []common.Address{}, err - } - addrBlockSigner := common.HexToAddress(common.BlockSigners) - signers, err = contracts.GetSignersByExecutingEVM(addrBlockSigner, client, prevBlock.Hash()) - if err != nil { - log.Error("Fail to get signers from block signer SC.", "error", err) - return []common.Address{}, err - } - validator, _ := engine.RecoverValidator(b.Header()) - creator, _ := engine.RecoverSigner(b.Header()) - signers = append(signers, validator) - signers = append(signers, creator) - for _, masternode := range masternodes { - for _, signer := range signers { - if signer == masternode { - filterSigners = append(filterSigners, masternode) - break + // Get block epoc latest. + lastCheckpointNumber := signedBlockNumber - (signedBlockNumber % s.b.ChainConfig().XDPoS.Epoch) + prevCheckpointBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(lastCheckpointNumber)) + if prevCheckpointBlock != nil { + masternodes := engine.GetMasternodesFromCheckpointHeader(prevCheckpointBlock.Header(), blockNumber, s.b.ChainConfig().XDPoS.Epoch) + signedBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(signedBlockNumber)) + if s.b.ChainConfig().IsTIPEVMSigner(latestBlockNumber) { + signers, err = GetSignersFromBlocks(s.b, signedBlock.NumberU64(), signedBlock.Hash(), masternodes) + } else { + signers, err = contracts.GetSignersByExecutingEVM(common.HexToAddress(common.BlockSigners), client, signedBlock.Hash()) + } + if err != nil { + log.Error("Fail to get signers from block signer SC.", "error", err) + return nil, err + } + validator, _ := engine.RecoverValidator(b.Header()) + creator, _ := engine.RecoverSigner(b.Header()) + signers = append(signers, validator) + signers = append(signers, creator) + countFinality := 0 + for _, masternode := range masternodes { + for _, signer := range signers { + if signer == masternode { + countFinality++ + filterSigners = append(filterSigners, masternode) + break + } } } } @@ -1617,4 +1624,53 @@ func (s *PublicNetAPI) PeerCount() hexutil.Uint { // Version returns the current ethereum protocol version. func (s *PublicNetAPI) Version() string { return fmt.Sprintf("%d", s.networkVersion) +} + +func GetSignersFromBlocks(b Backend, blockNumber uint64, blockHash common.Hash, masternodes []common.Address) ([]common.Address, error) { + var addrs []common.Address + mapMN := map[common.Address]bool{} + for _, node := range masternodes { + mapMN[node] = true + } + if engine, ok := b.GetEngine().(*XDPoS.XDPoS); ok { + limitNumber := blockNumber - blockNumber%b.ChainConfig().XDPoS.Epoch + 2*b.ChainConfig().XDPoS.Epoch - 1 + currentNumber := b.CurrentBlock().NumberU64() + if limitNumber > currentNumber { + limitNumber = currentNumber + } + for i := blockNumber + 1; i <= limitNumber; i++ { + header, err := b.HeaderByNumber(nil, rpc.BlockNumber(i)) + if err != nil { + return addrs, err + } + signData, ok := engine.BlockSigners.Get(header.Hash()) + var signTxs []*types.Transaction = nil + if !ok { + blockData, err := b.BlockByNumber(nil, rpc.BlockNumber(i)) + if err != nil { + return addrs, err + } + signTxs = []*types.Transaction{} + for _, tx := range blockData.Transactions() { + if tx.IsSigningTransaction() { + signTxs = append(signTxs, tx) + } + } + } else { + signTxs = signData.([]*types.Transaction) + } + for _, signtx := range signTxs { + blkHash := common.BytesToHash(signtx.Data()[len(signtx.Data())-32:]) + from := *signtx.From() + if blkHash == blockHash && mapMN[from] == true { + addrs = append(addrs, from) + delete(mapMN, from) + } + } + if len(mapMN) == 0 { + break + } + } + } + return addrs, nil } \ No newline at end of file diff --git a/miner/worker.go b/miner/worker.go index 21bf3bdae2..a810872b9c 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -18,6 +18,7 @@ package miner import ( "bytes" + "encoding/binary" "fmt" "math/big" "os" @@ -583,6 +584,9 @@ func (self *worker) commitNewWork() { if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 { misc.ApplyDAOHardFork(work.state) } + if self.config.IsTIPEVMSigner(header.Number) { + work.state.DeleteAddress(common.HexToAddress(common.BlockSigners)) + } // won't grasp txs at checkpoint var ( txs *types.TransactionsByPriceAndNonce @@ -671,6 +675,17 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB log.Trace("Ignoring reply protected special transaction", "hash", tx.Hash(), "eip155", env.config.EIP155Block) continue } + if tx.To().Hex() == common.BlockSigners { + if len(tx.Data()) < 68 { + log.Trace("Data special transaction invalid lenght", "hash", tx.Hash(), "data", len(tx.Data())) + continue + } + blkNumber := binary.BigEndian.Uint64(tx.Data()[8:40]) + if blkNumber >= env.header.Number.Uint64() || blkNumber <= env.header.Number.Uint64()-env.config.XDPoS.Epoch*2 { + log.Trace("Data special transaction invalid number", "hash", tx.Hash(), "blkNumber", blkNumber, "miner", env.header.Number) + continue + } + } // Start executing the transaction env.state.Prepare(tx.Hash(), common.Hash{}, env.tcount) nonce := env.state.GetNonce(from) diff --git a/params/config.go b/params/config.go index 39e7d14bc7..405eae8ad7 100644 --- a/params/config.go +++ b/params/config.go @@ -217,6 +217,10 @@ func (c *ChainConfig) IsTIP2019(num *big.Int) bool { return isForked(common.TIP2019Block, num) } +func (c *ChainConfig) IsTIPEVMSigner(num *big.Int) bool { + return isForked(common.TIPEVMSignerBlock, num) +} + // GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice). // // The returned GasTable's fields shouldn't, under any circumstances, be changed.