diff --git a/core/blockchain.go b/core/blockchain.go index 46e3454bd1..04451a9006 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -690,7 +690,7 @@ func (bc *BlockChain) procFutureBlocks() { // Insert one by one as chain insertion needs contiguous ancestry between blocks for i := range blocks { - bc.InsertChain(blocks[i : i+1]) + bc.InsertChain(blocks[i: i+1]) } } } @@ -699,9 +699,9 @@ func (bc *BlockChain) procFutureBlocks() { type WriteStatus byte const ( - NonStatTy WriteStatus = iota - CanonStatTy - SideStatTy + NonStatTy WriteStatus = iota + CanonStatTy + SideStatTy ) // Rollback is designed to remove a chain of links from the database that aren't @@ -1243,7 +1243,7 @@ func (st *insertStats) report(chain []*types.Block, index int, cache common.Stor if index == len(chain)-1 || elapsed >= statsReportLimit { var ( end = chain[index] - txs = countTransactions(chain[st.lastIndex : index+1]) + txs = countTransactions(chain[st.lastIndex: index+1]) ) context := []interface{}{ "blocks", st.processed, "txs", txs, "mgas", float64(st.usedGas) / 1000000, @@ -1633,17 +1633,16 @@ func (bc *BlockChain) UpdateM1() error { ms = append(ms, XDPoS.Masternode{Address: candidate, Stake: v.Uint64()}) } } - + log.Info("Ordered list of masternode candidates") + for _, m := range ms { + log.Info("", "address", m.Address.String(), "stake", m.Stake) + } if len(ms) == 0 { log.Info("No masternode candidates found. Keep the current masternodes set for the next epoch") } else { sort.Slice(ms, func(i, j int) bool { return ms[i].Stake >= ms[j].Stake }) - log.Info("Ordered list of masternode candidates") - for _, m := range ms { - log.Info("", "address", m.Address.String(), "stake", m.Stake) - } // update masternodes log.Info("Updating new set of masternodes") if len(ms) > common.MaxMasternodes { diff --git a/core/types/block.go b/core/types/block.go index f1aa43649f..e226d61fd5 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -85,6 +85,7 @@ type Header struct { MixDigest common.Hash `json:"mixHash" gencodec:"required"` Nonce BlockNonce `json:"nonce" gencodec:"required"` Validators []byte `json:"validators" gencodec:"required"` + Penalties []byte `json:"penalties" gencodec:"required"` } // field type overrides for gencodec @@ -320,6 +321,7 @@ func (b *Block) TxHash() common.Hash { return b.header.TxHash } func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash } func (b *Block) UncleHash() common.Hash { return b.header.UncleHash } func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) } +func (b *Block) Penalties() []byte { return common.CopyBytes(b.header.Penalties) } func (b *Block) Header() *Header { return CopyHeader(b.header) } diff --git a/eth/backend.go b/eth/backend.go index 7f18fe70b7..15c48a9400 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -51,7 +51,6 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" - "time" ) const NumOfMasternodes = 99 @@ -202,60 +201,92 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { return } if _, authorized := snap.Signers[eth.etherbase]; authorized { - // double validation - m2, err := getM2(snap, eth, block) - if err != nil { - log.Error("Fail to validate M2 condition for imported block", "error", err) + if err := contracts.CreateTransactionSign(chainConfig, eth.txPool, eth.accountManager, block, chainDb); err != nil { + log.Error("Fail to create tx sign for imported block", "error", err) return } - if eth.etherbase != m2 { - // firstly, look into txPool - pendingMap, err := eth.txPool.Pending() - if err != nil { - log.Error("Fail to get txPool pending", "err", err) - //reset pendingMap - pendingMap = map[common.Address]types.Transactions{} - } - txsSentFromM2 := pendingMap[m2] - if len(txsSentFromM2) > 0 { - for _, tx := range txsSentFromM2 { - if tx.To().String() == common.BlockSigners { - if err := contracts.CreateTransactionSign(chainConfig, eth.txPool, eth.accountManager, block, chainDb); err != nil { - log.Error("Fail to create tx sign for imported block", "error", err) - return - } - return - } - } - } - //then wait until signTx from m2 comes into txPool - txCh := make(chan core.TxPreEvent, txChanSize) - subEvent := eth.txPool.SubscribeTxPreEvent(txCh) - G: - select { - case event := <-txCh: - from, err := eth.txPool.GetSender(event.Tx) - if (err == nil) && (event.Tx.To().String() == common.BlockSigners) && (from == m2) { - if err := contracts.CreateTransactionSign(chainConfig, eth.txPool, eth.accountManager, block, chainDb); err != nil { - log.Error("Fail to create tx sign for imported block", "error", err) - return - } - } - //timeout 10s - case <-time.After(time.Duration(10) * time.Second): - break G - } - subEvent.Unsubscribe() - } else if err := contracts.CreateTransactionSign(chainConfig, eth.txPool, eth.accountManager, block, chainDb); err != nil { - log.Error("Fail to create tx sign for imported block", "error", err) - return - } - // end of double validation - } } eth.protocolManager.fetcher.SetImportedHook(importedHook) + // Hook will process when preparing block. + c.HookPrepare = func(header *types.Header, signers []common.Address) error { + client, err := eth.blockchain.GetClient() + if err != nil { + log.Error("Fail to connect IPC client for penalty.", "error", err) + } + number := header.Number.Int64() + // Check m2 exists on chaindb. + // Get secrets and opening at epoc block checkpoint. + if number > 0 && number%common.EpocBlockRandomize == 0 { + var candidates []int64 + lenSigners := int64(len(signers)) + + if lenSigners > 0 { + for _, addr := range signers { + random, err := contracts.GetRandomizeFromContract(client, addr) + if err != nil { + log.Error("Fail to get random m2 from contract.", "error", err) + } + candidates = append(candidates, random) + } + + // Get randomize m2 list. + m2, err := contracts.GenM2FromRandomize(candidates, lenSigners) + if err != nil { + log.Error("Can not get m2 from randomize SC", "error", err) + } + if len(m2) > 0 { + header.Validators = contracts.BuildValidatorFromM2(m2) + } + } + } + return nil + } + // Hook penalty. + c.HookPenalty = func(chain consensus.ChainReader, signers []common.Address, blockNumberEpoc uint64) ([]common.Address, error) { + client, err := eth.blockchain.GetClient() + if err != nil { + log.Error("Fail to connect IPC client for blockSigner", "error", err) + } + prevEpoc := blockNumberEpoc - chain.Config().XDPoS.Epoch + var penSigners []common.Address + if prevEpoc > 0 { + prevHeader := chain.GetHeaderByNumber(prevEpoc) + prevSigners := c.GetMasternodes(chain, prevHeader) + for _, signer := range signers { + for _, prevSigner := range prevSigners { + if signer == prevSigner { + penSigners = append(penSigners, signer) + } + } + } + if len(penSigners) > 0 { + blockSignerAddr := common.HexToAddress(common.BlockSigners) + // Loop for each block to check missing sign. + for i := prevEpoc; i <= blockNumberEpoc; i++ { + blockHeader := chain.GetHeaderByNumber(i) + if len(penSigners) > 0 { + signedMasternodes, _ := contracts.GetSignersFromContract(blockSignerAddr, client, blockHeader.Hash()) + if len(signedMasternodes) > 0 { + // Check signer signed? + for _, signed := range signedMasternodes { + for j, addr := range penSigners { + if signed == addr { + // Remove it from dupSigners. + penSigners = append(penSigners[:j], penSigners[j+1:]...) + } + } + } + } + } + } + } + } + + return penSigners, nil + } + // Hook reward for XDPoS validator. c.HookReward = func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) error { client, err := eth.blockchain.GetClient() @@ -298,39 +329,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } } } - - // Check m2 exists on chaindb. - // Get secrets and opening at epoc block checkpoint. - if number > 0 && number%common.EpocBlockRandomize == 0 { - var candidates []int64 - // Get signers from snapshot. - snap, err := c.GetSnapshot(eth.blockchain, chain.CurrentHeader()) - if err != nil { - log.Error("Fail to get snapshot for get secret and opening.", "error", err) - return err - } - signers := snap.Signers - lenSigners := int64(len(signers)) - - if lenSigners > 0 { - for addr := range signers { - random, err := contracts.GetRandomizeFromContract(client, addr) - if err != nil { - log.Error("Fail to get random m2 from contract.", "error", err) - } - candidates = append(candidates, random) - } - - // Get randomize m2 list. - m2, err := contracts.GenM2FromRandomize(candidates, lenSigners) - if err != nil { - log.Error("Can not get m2 from randomize SC", "error", err) - } - if len(m2) > 0 { - header.Validators = contracts.BuildValidatorFromM2(m2) - } - } - } return nil } @@ -339,25 +337,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { return eth, nil } -func getM2(snap *XDPoS.Snapshot, eth *Ethereum, block *types.Block) (common.Address, error) { - epoch := eth.chainConfig.XDPoS.Epoch - no := block.NumberU64() - cpNo := no - if no%epoch != 0 { - cpNo = no - (no % epoch) - } - cpBlk := eth.blockchain.GetBlockByNumber(cpNo) - m, err := contracts.GetM1M2FromCheckpointBlock(cpBlk) - if err != nil { - return common.Address{}, err - } - m1, err := XDPoS.WhoIsCreator(snap, block.Header()) - if err != nil { - return common.Address{}, err - } - return m[m1], nil -} - func makeExtraData(extra []byte) []byte { if len(extra) == 0 { // create default extradata diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 2fc378b02f..78b9a37abc 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -817,6 +817,7 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx "transactionsRoot": head.TxHash, "receiptsRoot": head.ReceiptHash, "validators": hexutil.Bytes(head.Validators), + "penalties": hexutil.Bytes(head.Penalties), } if inclTx {