mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
Add penalty feature for prevent signer without sign in epoc make slow…
This commit is contained in:
parent
b8cb600964
commit
f5152bf0cf
4 changed files with 92 additions and 111 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
||||
|
|
|
|||
181
eth/backend.go
181
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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue