github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/consensus/podc/backend/backend.go (about)

     1  
     2  // Copyright 2017 AMIS Technologies
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package backend
    19  
    20  import (
    21  "crypto/ecdsa"
    22  "sync"
    23  
    24  "github.com/ethereum/go-ethereum/common"
    25  "github.com/ethereum/go-ethereum/consensus"
    26  "github.com/ethereum/go-ethereum/consensus/podc"
    27   podcCore "github.com/ethereum/go-ethereum/consensus/podc/core"
    28  "github.com/ethereum/go-ethereum/consensus/podc/validator"
    29  "github.com/ethereum/go-ethereum/core"
    30  "github.com/ethereum/go-ethereum/core/types"
    31  "github.com/ethereum/go-ethereum/crypto"
    32  "github.com/ethereum/go-ethereum/ethdb"
    33  "github.com/ethereum/go-ethereum/event"
    34  "github.com/ethereum/go-ethereum/log"
    35  lru "github.com/hashicorp/golang-lru"
    36  )
    37  
    38  func New(config *podc.Config, eventMux *event.TypeMux, privateKey *ecdsa.PrivateKey, db ethdb.Database) consensus.PoDC {
    39  	// Allocate the snapshot caches and create the engine
    40  	recents, _ := lru.NewARC(inmemorySnapshots)
    41  	backend := &simpleBackend{
    42  		config:           config,
    43  		eventMux:         eventMux,
    44  		//istanbulEventMux: new(event.TypeMux),
    45  		podcEventMux: new(event.TypeMux),
    46  		privateKey:       privateKey,
    47  		address:          crypto.PubkeyToAddress(privateKey.PublicKey),
    48  		logger:           log.New("backend", "simple"),
    49  		db:               db,
    50  		commitCh:         make(chan *types.Block, 1),
    51  		recents:          recents,
    52  		candidates:       make(map[common.Address]bool),
    53  	}
    54  	return backend
    55  }
    56  
    57  // ----------------------------------------------------------------------------
    58  
    59  type simpleBackend struct {
    60  	config           *podc.Config
    61  	eventMux         *event.TypeMux
    62  	podcEventMux     *event.TypeMux
    63  	privateKey       *ecdsa.PrivateKey
    64  	address          common.Address
    65  
    66  	core             podcCore.Engine
    67  	logger           log.Logger
    68  	quitSync         chan struct{}
    69  	db               ethdb.Database
    70  	timeout          uint64
    71  	chain            consensus.ChainReader
    72  	inserter         func(block *types.Block) error
    73  
    74  	// the channels for istanbul engine notifications
    75  	commitCh          chan *types.Block
    76  	proposedBlockHash common.Hash
    77  	sealMu            sync.Mutex
    78  
    79  	// Current list of candidates we are pushing
    80  	candidates map[common.Address]bool
    81  	// Protects the signer fields
    82  	candidatesLock sync.RWMutex
    83  	// Snapshots for recent block to speed up reorgs
    84  	recents *lru.ARCCache
    85  }
    86  
    87  // Address implements istanbul.Backend.Address
    88  func (sb *simpleBackend) Address() common.Address {
    89  	return sb.address
    90  }
    91  
    92  
    93  //Validators implements PoDC.Backend.Validators
    94  func (sb *simpleBackend) Validators(proposal podc.Proposal) podc.ValidatorSet {
    95  	snap, err := sb.snapshot(sb.chain, proposal.Number().Uint64(), proposal.Hash(), nil)
    96  	if err != nil {
    97  		return validator.NewSet(nil, sb.config.ProposerPolicy)  // 지금은 라운드로빈으로, 동작 예정, 
    98  	}
    99  	return snap.ValSet
   100  }
   101  
   102  func (sb *simpleBackend) Send(payload []byte, target common.Address) error {
   103  	go sb.eventMux.Post(podc.ConsensusDataEvent{
   104  		Target: target,
   105  		Data:   payload,
   106  	})
   107  	return nil
   108  }
   109  
   110  
   111  //
   112  
   113  // Broadcast implements podc.Backend.Send
   114  func (sb *simpleBackend) Broadcast(valSet podc.ValidatorSet, payload []byte) error {
   115  
   116  	// 모든 Validator 리스트에 다 보냄.
   117  	for _, val := range valSet.List() {
   118  		if val.Address() == sb.Address() {
   119  			// send to self
   120  			msg := podc.MessageEvent{
   121  				Payload: payload,
   122  			}
   123  			go sb.podcEventMux.Post(msg)
   124  
   125  		} else {
   126  			// send to other peers
   127  			sb.Send(payload, val.Address())
   128  
   129  		}
   130  	}
   131  	return nil
   132  }
   133  
   134  func (sb *simpleBackend) Multicast(payload []byte, targets []common.Address) error {
   135  	for _, addr := range targets {
   136  		if addr == sb.Address() {
   137  			msg := podc.MessageEvent{
   138  				Payload: payload,
   139  			}
   140  			go sb.podcEventMux.Post(msg)
   141  		} else {
   142  			sb.Send(payload, addr)
   143  		}
   144  	}
   145  	return nil
   146  }
   147  
   148  // Commit implements podc.Backend.Commit
   149  func (sb *simpleBackend) Commit(proposal podc.Proposal, seals []byte) error {
   150  	// Check if the proposal is a valid block
   151  	block := &types.Block{}
   152  	block, ok := proposal.(*types.Block)
   153  	if !ok {
   154  		sb.logger.Error("Invalid proposal, %v", proposal)
   155  		return errInvalidProposal
   156  	}
   157  
   158  	h := block.Header()
   159  	// Append seals into extra-data
   160  	err := writeCommittedSeals(h, seals)
   161  	if err != nil {
   162  		return err
   163  	}
   164  	// update block's header
   165  	block = block.WithSeal(h)
   166  
   167  	sb.logger.Info("Committed", "address", sb.Address(), "hash", proposal.Hash(), "number", proposal.Number().Uint64())
   168  	// - if the proposed and committed blocks are the same, send the proposed hash
   169  	//   to commit channel, which is being watched inside the engine.Seal() function.
   170  	// - otherwise, we try to insert the block.
   171  	// -- if success, the ChainHeadEvent event will be broadcasted, try to build
   172  	//    the next block and the previous Seal() will be stopped.
   173  	// -- otherwise, a error will be returned and a round change event will be fired.
   174  	
   175  	// TODO-REAP: temporarily disable
   176  	// if sb.proposedBlockHash == block.Hash() {
   177  	// 	// feed block hash to Seal() and wait the Seal() result
   178  	// 	sb.commitCh <- block
   179  	// 	// TODO: how do we check the block is inserted correctly?
   180  	// 	return nil
   181  	// }
   182  
   183  	return sb.inserter(block)
   184  }
   185  
   186  // NextRound will broadcast ChainHeadEvent to trigger next seal()
   187  
   188  func (sb *simpleBackend) NextRound() error {
   189  	header := sb.chain.CurrentHeader()
   190  	sb.logger.Debug("NextRound", "address", sb.Address(), "current_hash", header.Hash(), "current_number", header.Number)
   191  	go sb.eventMux.Post(core.ChainHeadEvent{})
   192  	return nil
   193  }
   194  
   195  // EventMux implements PoDC.Backend.EventMux
   196  func (sb *simpleBackend) EventMux() *event.TypeMux {
   197  	return sb.podcEventMux
   198  }
   199  
   200  // Verify implements podc.Backend.Verify
   201  func (sb *simpleBackend) Verify(proposal podc.Proposal) error {
   202  	// Check if the proposal is a valid block
   203  	block := &types.Block{}
   204  	block, ok := proposal.(*types.Block)
   205  	if !ok {
   206  		sb.logger.Error("Invalid proposal, %v", proposal)
   207  		return errInvalidProposal
   208  	}
   209  	// verify the header of proposed block
   210  	err := sb.VerifyHeader(sb.chain, block.Header(), false)
   211  	// Ignore errEmptyCommittedSeals error because we don't have the committed seals yet
   212  	if err != nil && err != errEmptyCommittedSeals {
   213  		return err
   214  	}
   215  	return nil
   216  }
   217  
   218  // Sign implements podc.Backend.Sign
   219  func (sb *simpleBackend) Sign(data []byte) ([]byte, error) {
   220  	hashData := crypto.Keccak256([]byte(data))
   221  	return crypto.Sign(hashData, sb.privateKey)
   222  }
   223  
   224  func (sb *simpleBackend) CheckSignature(data []byte, address common.Address, sig []byte) error {
   225  	signer, err := podc.GetSignatureAddress(data, sig)
   226  	if err != nil {
   227  		log.Error("Failed to get signer address", "err", err)
   228  		return err
   229  	}
   230  	// Compare derived addresses
   231  	if signer != address {
   232  		return errInvalidSignature
   233  	}
   234  	return nil
   235  }