{
"consensus":{
"dpos": {
- "period": 1,
+ "period": 3,
"epoch": 300,
"maxSignersCount": 1,
"minVoterBalance": 0,
// Engine is an algorithm agnostic consensus engine.
type Engine interface {
- // Author retrieves the Ethereum address of the account that minted the given
- // block, which may be different from the header's coinbase if a consensus
- // engine is based on signatures.
- Author(header *types.BlockHeader, c chain.Chain) (string, error)
-
- // VerifyHeader checks whether a header conforms to the consensus rules of a
- // given engine. Verifying the seal may be done optionally here, or explicitly
- // via the VerifySeal method.
- VerifyHeader(c chain.Chain, header *types.BlockHeader, seal bool) error
-
- // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers
- // concurrently. The method returns a quit channel to abort the operations and
- // a results channel to retrieve the async verifications (the order is that of
- // the input slice).
- VerifyHeaders(c chain.Chain, headers []*types.BlockHeader, seals []bool) (chan<- struct{}, <-chan error)
// VerifySeal checks whether the crypto seal on a header is valid according to
// the consensus rules of the given engine.
}
}
}
- /*
- if height > 1 {
- headerExtra.ModifyPredecessorVotes = d.processPredecessorVoter(headerExtra.ModifyPredecessorVotes, stake, from, to, snap)
- }
- */
}
}
}
func (d *Dpos) processEventVote(currentBlockVotes []Vote, stake uint64, voter, to string) []Vote {
-
- //if new(big.Int).SetUint64(stake).Cmp(d.config.MinVoterBalance) > 0 {
- currentBlockVotes = append(currentBlockVotes, Vote{
- Voter: voter,
- Candidate: to,
- Stake: stake,
- })
- //}
+ if stake >= d.config.MinVoterBalance {
+ currentBlockVotes = append(currentBlockVotes, Vote{
+ Voter: voter,
+ Candidate: to,
+ Stake: stake,
+ })
+ }
return currentBlockVotes
}
if extraVanity+extraSeal > len(confirmedHeader.Extra) {
return currentBlockConfirmations
}
- //err = rlp.DecodeBytes(confirmedHeader.Extra[extraVanity:len(confirmedHeader.Extra)-extraSeal], &confirmedHeaderExtra)
if err := json.Unmarshal(confirmedHeader.Extra[extraVanity:len(confirmedHeader.Extra)-extraSeal], &confirmedHeaderExtra); err != nil {
log.Info("Fail to decode parent header", "err", err)
return currentBlockConfirmations
return currentBlockConfirmations
}
-
-func (d *Dpos) processPredecessorVoter(modifyPredecessorVotes []Vote, stake uint64, voter, to string, snap *Snapshot) []Vote {
- if stake > 0 {
- if snap.isVoter(voter) {
- modifyPredecessorVotes = append(modifyPredecessorVotes, Vote{
- Voter: voter,
- Candidate: "",
- Stake: stake,
- })
- }
- if snap.isVoter(to) {
- modifyPredecessorVotes = append(modifyPredecessorVotes, Vote{
- Voter: to,
- Candidate: "",
- Stake: stake,
- })
- }
-
- }
- return modifyPredecessorVotes
-}
recents *lru.ARCCache // Snapshots for recent block to speed up reorgs
signatures *lru.ARCCache // Signatures of recent blocks to speed up mining
signer string // Ethereum address of the signing key
- signFn SignerFn // Signer function to authorize hashes with
- signTxFn SignTxFn // Sign transaction function to sign tx
lock sync.RWMutex // Protects the signer fields
lcsc uint64 // Last confirmed side chain
}
-// SignerFn is a signer callback function to request a hash to be signed by a backing account.
-type SignerFn func(string, []byte) ([]byte, error)
-
-// SignTxFn is a signTx
-type SignTxFn func(string, *bc.Tx, *big.Int) (*bc.Tx, error)
-
//
func ecrecover(header *types.BlockHeader, sigcache *lru.ARCCache, c chain.Chain) (string, error) {
-
xpub := &chainkd.XPub{}
xpub.UnmarshalText(header.Coinbase)
derivedPK := xpub.PublicKey()
}
// Authorize injects a private key into the consensus engine to mint new blocks with.
-func (d *Dpos) Authorize(signer string /*, signFn SignerFn*/) {
+func (d *Dpos) Authorize(signer string) {
d.lock.Lock()
defer d.lock.Unlock()
-
d.signer = signer
- //d.signFn = signFn
-}
-
-// 从BLockHeader中获取到地址
-func (d *Dpos) Author(header *types.BlockHeader, c chain.Chain) (string, error) {
- return ecrecover(header, d.signatures, c)
-}
-
-func (d *Dpos) VerifyHeader(c chain.Chain, header *types.BlockHeader, seal bool) error {
- return d.verifyCascadingFields(c, header, nil)
-}
-
-func (d *Dpos) VerifyHeaders(c chain.Chain, headers []*types.BlockHeader, seals []bool) (chan<- struct{}, <-chan error) {
- return nil, nil
}
func (d *Dpos) VerifySeal(c chain.Chain, header *types.BlockHeader) error {
- return nil
-}
-
-func (d *Dpos) verifyHeader(c chain.Chain, header *types.BlockHeader, parents []*types.BlockHeader) error {
- return nil
+ return d.verifyCascadingFields(c, header, nil)
}
func (d *Dpos) verifyCascadingFields(c chain.Chain, header *types.BlockHeader, parents []*types.BlockHeader) error {
return err
}
- // Resolve the authorization key and check against signers
- signer, err := ecrecover(header, d.signatures, c)
- if err != nil {
- return err
- }
+ signer := ""
if height > d.config.MaxSignerCount {
var (
if err != nil {
return err
}
+ signer = currentCoinbase.EncodeAddress()
parentHeaderExtra := HeaderExtra{}
if err = json.Unmarshal(parent.Extra[extraVanity:len(parent.Extra)-extraSeal], &parentHeaderExtra); err != nil {
}
}
if height%d.config.MaxSignerCount == 0 {
- //currentHeaderExtra.LoopStartTime = header.Time.Uint64()
currentHeaderExtra.LoopStartTime = currentHeaderExtra.LoopStartTime + d.config.Period*d.config.MaxSignerCount
// create random signersQueue in currentHeaderExtra by snapshot.Tally
currentHeaderExtra.SignerQueue = []string{}
if err != nil {
return nil, err
}
- if err := d.VerifyHeader(c, genesis, false); err != nil {
+ if err := d.VerifySeal(c, genesis); err != nil {
return nil, err
}
}
func (s *Snapshot) createSignerQueue() ([]string, error) {
-
if (s.Number+1)%s.config.MaxSignerCount != 0 || s.Hash != s.HistoryHash[len(s.HistoryHash)-1] {
return nil, errCreateSignerQueueNotAllowed
}
"time"
lru "github.com/hashicorp/golang-lru"
- "github.com/vapor/common"
"github.com/vapor/config"
- "github.com/vapor/consensus"
- "github.com/vapor/crypto"
- "github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/protocol"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
return nil, err
}
- xpub := &chainkd.XPub{}
- xpub.UnmarshalText(header.Coinbase)
- derivedPK := xpub.PublicKey()
- pubHash := crypto.Ripemd160(derivedPK)
- address, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)
- if err != nil {
- return nil, err
- }
- if coinbase != address.EncodeAddress() {
- return nil, errUnauthorized
- }
-
headerExtra := HeaderExtra{}
if err := json.Unmarshal(header.Extra[extraVanity:len(header.Extra)-extraSeal], &headerExtra); err != nil {
return nil, err
// deal the new vote from voter
snap.updateSnapshotByVotes(headerExtra.CurrentBlockVotes, header.Height)
- // deal the voter which balance modified
- //snap.updateSnapshotByMPVotes(headerExtra.ModifyPredecessorVotes)
-
// deal the snap related with punished
- //snap.updateSnapshotForPunish(headerExtra.SignerMissing, header.Height, header.Coinbase)
+ snap.updateSnapshotForPunish(headerExtra.SignerMissing, header.Height, coinbase)
// deal proposals
snap.updateSnapshotByProposals(headerExtra.CurrentBlockProposals, header.Height)
for address, tally := range s.Tally {
if targetTally, ok := tallyTarget[address]; ok && targetTally == tally {
continue
+ } else {
+ return errIncorrectTallyCount
}
}
}
case proposalTypeMinerRewardDistributionModify:
minerRewardPerThousand = s.Proposals[hashKey].MinerRewardPerThousand
-
}
}
-
}
-
}
-
}
func (s *Snapshot) updateSnapshotByProposals(proposals []Proposal, headerHeight uint64) {
}
func (s *Snapshot) updateSnapshotForExpired() {
-
// deal the expired vote
var expiredVotes []*Vote
for voterAddress, voteNumber := range s.Voters {
for _, expiredVote := range expiredVotes {
s.Tally[expiredVote.Candidate] -= expiredVote.Stake
// TODO
- /*
- if s.Tally[expiredVote.Candidate] == 0 {
- delete(s.Tally, expiredVote.Candidate)
- }
- delete(s.Votes, expiredVote.Voter)
- delete(s.Voters, expiredVote.Voter)
- */
+ if s.Tally[expiredVote.Candidate] == 0 {
+ delete(s.Tally, expiredVote.Candidate)
+ }
+ delete(s.Votes, expiredVote.Voter)
+ delete(s.Voters, expiredVote.Voter)
}
}
}
// TODO
- /*
- // remove 0 stake tally
- for address, tally := range s.Tally {
- if tally <= 0 {
- delete(s.Tally, address)
- }
+ // remove 0 stake tally
+
+ for address, tally := range s.Tally {
+ if tally <= 0 && uint64(len(s.Tally)) > s.config.MaxSignerCount {
+ delete(s.Tally, address)
}
- */
+ }
}
func (s *Snapshot) updateSnapshotByConfirmations(confirmations []Confirmation) {
}
func (s *Snapshot) updateSnapshotForPunish(signerMissing []string, headerNumber uint64, coinbase string) {
- // set punished count to half of origin in Epoch
- /*
- if headerNumber.Uint64()%s.config.Epoch == 0 {
- for bePublished := range s.Punished {
- if count := s.Punished[bePublished] / 2; count > 0 {
- s.Punished[bePublished] = count
- } else {
- delete(s.Punished, bePublished)
- }
- }
- }
- */
// punish the missing signer
for _, signerMissing := range signerMissing {
if _, ok := s.Punished[signerMissing]; ok {
// get last block number meet the confirm condition
func (s *Snapshot) getLastConfirmedBlockNumber(confirmations []Confirmation) *big.Int {
-
cpyConfirmations := make(map[uint64][]string)
for blockNumber, confirmers := range s.Confirmations {
cpyConfirmations[blockNumber] = make([]string, len(confirmers))
}
}
if addConfirmation == true {
-
cpyConfirmations[confirmation.BlockNumber] = append(cpyConfirmations[confirmation.BlockNumber], confirmation.Signer)
}
}
updateNumWorkers chan struct{}
quit chan struct{}
newBlockCh chan *bc.Hash
- Authoritys map[string]string
- position uint64
engine engine.Engine
}
func NewMiner(c *protocol.Chain, accountManager *account.Manager, txPool *protocol.TxPool, newBlockCh chan *bc.Hash, engine engine.Engine) *Miner {
- authoritys := make(map[string]string)
- var position uint64
dpos, ok := engine.(*dpos.Dpos)
if !ok {
log.Error("Only the dpos engine was allowed")
numWorkers: defaultNumWorkers,
updateNumWorkers: make(chan struct{}),
newBlockCh: newBlockCh,
- Authoritys: authoritys,
- position: position,
engine: dpos,
}
}
//
// It must be run as a goroutine.
func (m *Miner) generateBlocks(quit chan struct{}) {
- ticker := time.NewTicker(time.Second * hashUpdateSecs)
- defer ticker.Stop()
out:
for {
break out
default:
}
- /*
- engine, ok := m.engine.(*dpos.Dpos)
- if !ok {
- log.Error("Only the dpos engine was allowed")
- return
- }
- header := m.chain.BestBlockHeader()
- isSeal, err := engine.IsSealer(m.chain, header.Hash(), header, uint64(time.Now().Unix()))
- if err != nil {
- log.WithFields(log.Fields{"module": module, "error": err}).Error("Determine whether seal is wrong")
- continue
- }
- */
- isSeal := true
- if isSeal {
- block, err := mining.NewBlockTemplate(m.chain, m.txPool, m.accountManager, m.engine)
- if err != nil {
- log.Errorf("Mining: failed on create NewBlockTemplate: %v", err)
- time.Sleep(3 * time.Second)
- continue
- }
- if block == nil {
- time.Sleep(3 * time.Second)
- continue
- }
- block, err = m.engine.Seal(m.chain, block)
- if err != nil {
- log.Errorf("Seal, %v", err)
- continue
- }
- m.chain.SetConsensusEngine(m.engine)
- if isOrphan, err := m.chain.ProcessBlock(block); err == nil {
- log.WithFields(log.Fields{
- "height": block.BlockHeader.Height,
- "isOrphan": isOrphan,
- "tx": len(block.Transactions),
- }).Info("Miner processed block")
-
- blockHash := block.Hash()
- m.newBlockCh <- &blockHash
- } else {
- log.WithField("height", block.BlockHeader.Height).Errorf("Miner fail on ProcessBlock, %v", err)
- }
+ block, err := mining.NewBlockTemplate(m.chain, m.txPool, m.accountManager, m.engine)
+ if err != nil {
+ log.Errorf("Mining: failed on create NewBlockTemplate: %v", err)
+ time.Sleep(1 * time.Second)
+ continue
+ }
+ if block == nil {
+ time.Sleep(1 * time.Second)
+ continue
+ }
+ block, err = m.engine.Seal(m.chain, block)
+ if err != nil {
+ log.Errorf("Seal, %v", err)
+ continue
}
- time.Sleep(3 * time.Second)
+ m.chain.SetConsensusEngine(m.engine)
+ if isOrphan, err := m.chain.ProcessBlock(block); err == nil {
+ log.WithFields(log.Fields{
+ "height": block.BlockHeader.Height,
+ "isOrphan": isOrphan,
+ "tx": len(block.Transactions),
+ }).Info("Miner processed block")
+
+ blockHash := block.Hash()
+ m.newBlockCh <- &blockHash
+ } else {
+ log.WithField("height", block.BlockHeader.Height).Errorf("Miner fail on ProcessBlock, %v", err)
+ }
+ // confirm block
+ m.sendConfirmTx(block.Height - 1)
+ time.Sleep(time.Duration(config.CommonConfig.Consensus.Dpos.Period) * time.Second)
}
m.workerWg.Done()
}
+func (m *Miner) sendConfirmTx(height uint64) error {
+ return nil
+}
+
// miningWorkerController launches the worker goroutines that are used to
// generate block templates and solve them. It also provides the ability to
// dynamically adjust the number of running worker goroutines.
address, _ := common.DecodeAddress(config.CommonConfig.Consensus.Dpos.Coinbase, &consensus.ActiveNetParams)
redeemContract := address.ScriptAddress()
script, _ = vmutil.P2WPKHProgram(redeemContract)
- /*
- if accountManager == nil {
- script, err = vmutil.DefaultCoinbaseProgram()
- } else {
- script, err = accountManager.GetCoinbaseControlProgram()
- arbitrary = append(arbitrary, accountManager.GetCoinbaseArbitrary()...)
- }
- */
if err != nil {
return nil, err
}
Timestamp: uint64(time.Now().Unix()),
BlockCommitment: types.BlockCommitment{},
Coinbase: xpub,
- //Extra: make([]byte, 32+65),
}
if err := engine.Prepare(c, &header); err != nil {
}
}
- if txFee == 0 {
- return nil, nil
- }
-
if err := engine.Finalize(c, &header, txEntries[1:]); err != nil {
return nil, err
}
log "github.com/sirupsen/logrus"
"github.com/vapor/account"
- "github.com/vapor/mining"
"github.com/vapor/protocol"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
// generateBlock generates a block template to mine
func (m *MiningPool) generateBlock() {
- m.mutex.Lock()
- defer m.mutex.Unlock()
- block, err := mining.NewBlockTemplate(m.chain, m.txPool, m.accountManager)
- if err != nil {
- log.Errorf("miningpool: failed on create NewBlockTemplate: %v", err)
- return
- }
- m.block = block
}
// GetWork will return a block header for p2p mining
case *GetMerkleBlockMessage:
sm.handleGetMerkleBlockMsg(peer, msg)
+ // TODO PBFT消息
+
default:
log.WithFields(log.Fields{
"module": logModule,
bcBlock := types.MapBlock(block)
parent := c.index.GetNode(&block.PreviousBlockHash)
- if err := validation.ValidateBlock(bcBlock, parent, block, c, c.engine, c.Authoritys, c.position); err != nil {
+ if err := validation.ValidateBlock(bcBlock, parent, block, c, c.engine); err != nil {
return errors.Sub(ErrBadBlock, err)
}
if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil {
store Store
processBlockCh chan *processBlockMsg
- cond sync.Cond
- bestNode *state.BlockNode
- Authoritys map[string]string
- position uint64
- engine engine.Engine
+ cond sync.Cond
+ bestNode *state.BlockNode
+ engine engine.Engine
}
// NewChain returns a new Chain using store as the underlying storage.
return c, nil
}
-func (c *Chain) SetAuthoritys(authoritys map[string]string) {
- c.Authoritys = authoritys
-}
-
-func (c *Chain) SetPosition(position uint64) {
- c.position = position
-}
-
func (c *Chain) SetConsensusEngine(engine engine.Engine) {
c.engine = engine
}
if err := checkBlockTime(b, parent); err != nil {
return err
}
- if err := engine.VerifyHeader(c, &block.BlockHeader, false); err != nil {
+ if err := engine.VerifySeal(c, &block.BlockHeader); err != nil {
return err
}
}
// ValidateBlock validates a block and the transactions within.
-func ValidateBlock(b *bc.Block, parent *state.BlockNode, block *types.Block, c chain.Chain, engine engine.Engine, authoritys map[string]string, position uint64) error {
+func ValidateBlock(b *bc.Block, parent *state.BlockNode, block *types.Block, c chain.Chain, engine engine.Engine) error {
startTime := time.Now()
if err := ValidateBlockHeader(b, block, parent, c, engine); err != nil {
return err
}
- /*
- time.Sleep(3 * time.Second)
- // 验证出块人
- controlProgram := hex.EncodeToString(block.Proof.ControlProgram)
- xpub := &chainkd.XPub{}
- xpub.UnmarshalText([]byte(authoritys[controlProgram]))
- msg := block.BlockCommitment.TransactionsMerkleRoot.Bytes()
- if !xpub.Verify(msg, block.Proof.Sign) {
- return errors.New("Verification signature failed")
- }
- */
blockGasSum := uint64(0)
coinbaseAmount := consensus.BlockSubsidy(b.BlockHeader.Height)
b.TransactionStatus = bc.NewTransactionStatus()
}
}
- block, err := mining.NewBlockTemplate(chain, txPool, nil)
+ block, err := mining.NewBlockTemplate(chain, txPool, nil, nil)
if err != nil {
return err
}
package test
import (
- "encoding/hex"
-
"github.com/vapor/consensus"
"github.com/vapor/crypto"
"github.com/vapor/crypto/ed25519/chainkd"
return nil
}
-func setAuthoritys(chain *protocol.Chain) {
- authoritys := make(map[string]string)
- xpubStr := "96bc2ad4b1c2db399990c811c4367688cbb7867612bb9d04e4dc7848e425c6395264d3b177a96646bc0ce517ae7fd63504c183ab6d330dea184331a4cf5912d5"
- var xpub chainkd.XPub
- xpub.UnmarshalText([]byte(xpubStr))
-
- pubHash := crypto.Ripemd160(xpub.PublicKey())
- control, _ := vmutil.P2WPKHProgram([]byte(pubHash))
- key := hex.EncodeToString(control)
- authoritys[key] = xpub.String()
-
- chain.SetAuthoritys(authoritys)
-}
-
// SolveAndUpdate solve difficulty and update chain status
func SolveAndUpdate(chain *protocol.Chain, block *types.Block) error {
_, err := chain.ProcessBlock(block)
txPool := protocol.NewTxPool(store)
chain, err := protocol.NewChain(store, txPool)
consensus.ActiveNetParams.Signer = "78673764e0ba91a4c5ba9ec0c8c23c69e3d73bf27970e05e0a977e81e13bde475264d3b177a96646bc0ce517ae7fd63504c183ab6d330dea184331a4cf5912d5"
- setAuthoritys(chain)
return chain, store, txPool, err
}
}
func getPeginInfo() (map[string]string, error) {
- resp, err := http.Get("http://127.0.0.1:8000/api/get_pegin_address")
+ resp, err := http.Get("http://127.0.0.1:8080/api/get_pegin_address")
if err != nil {
return nil, err
}
"maxSignersCount": 1,
"minVoterBalance": 0,
"genesisTimestamp": 1524549600,
- "coinbase": "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep",
- "xprv": "a8e281b615809046698fb0b0f2804a36d824d48fa443350f10f1b80649d39e5f1e85cf9855548915e36137345910606cbc8e7dd8497c831dce899ee6ac112445",
+ "coinbase": "vsm1qy7ml46ehvsny47l7cl76ejeye7ngkvh3tkp7n7",
+ "xprv": "c0d652077ae5d056c143ef94d0fa2042d9083d13174ae47d88ece000c4cc2d4d7200dba78d5f21e1c3d35b351fbd410b4cf453d7cd425f8d47acec25e8a271e9",
"signers": [
- "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep"
+ "vsm1qkm743xmgnvh84pmjchq2s4tnfpgu9ae2f9slep",
+ "vsm1qy7ml46ehvsny47l7cl76ejeye7ngkvh3tkp7n7"
]
}
}