More mining rework
This commit is contained in:
parent
2be2fc7974
commit
ae837c4719
@ -304,6 +304,9 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block {
|
|||||||
func (block *Block) String() string {
|
func (block *Block) String() string {
|
||||||
return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions))
|
return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions))
|
||||||
}
|
}
|
||||||
|
func (block *Block) GetRoot() interface{} {
|
||||||
|
return block.state.trie.Root
|
||||||
|
}
|
||||||
|
|
||||||
//////////// UNEXPORTED /////////////////
|
//////////// UNEXPORTED /////////////////
|
||||||
func (block *Block) header() []interface{} {
|
func (block *Block) header() []interface{} {
|
||||||
|
@ -44,7 +44,6 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block {
|
|||||||
hash = bc.LastBlockHash
|
hash = bc.LastBlockHash
|
||||||
lastBlockTime = bc.CurrentBlock.Time
|
lastBlockTime = bc.CurrentBlock.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
block := CreateBlock(
|
block := CreateBlock(
|
||||||
root,
|
root,
|
||||||
hash,
|
hash,
|
||||||
@ -181,8 +180,8 @@ func (bc *BlockChain) SetTotalDifficulty(td *big.Int) {
|
|||||||
// Add a block to the chain and record addition information
|
// Add a block to the chain and record addition information
|
||||||
func (bc *BlockChain) Add(block *Block) {
|
func (bc *BlockChain) Add(block *Block) {
|
||||||
bc.writeBlockInfo(block)
|
bc.writeBlockInfo(block)
|
||||||
|
|
||||||
// Prepare the genesis block
|
// Prepare the genesis block
|
||||||
|
|
||||||
bc.CurrentBlock = block
|
bc.CurrentBlock = block
|
||||||
bc.LastBlockHash = block.Hash()
|
bc.LastBlockHash = block.Hash()
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PoW interface {
|
type PoW interface {
|
||||||
Search(block *Block, minerChan chan ethutil.React) []byte
|
Search(block *Block, reactChan chan ethutil.React) []byte
|
||||||
Verify(hash []byte, diff *big.Int, nonce []byte) bool
|
Verify(hash []byte, diff *big.Int, nonce []byte) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ type EasyPow struct {
|
|||||||
hash *big.Int
|
hash *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pow *EasyPow) Search(block *Block, minerChan chan ethutil.React) []byte {
|
func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte {
|
||||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
hash := block.HashNoNonce()
|
hash := block.HashNoNonce()
|
||||||
diff := block.Difficulty
|
diff := block.Difficulty
|
||||||
@ -28,15 +28,9 @@ func (pow *EasyPow) Search(block *Block, minerChan chan ethutil.React) []byte {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case chanMessage := <-minerChan:
|
case <-reactChan:
|
||||||
if _, ok := chanMessage.Resource.(*Block); ok {
|
log.Println("[pow] Received reactor event; breaking out.")
|
||||||
log.Println("BREAKING OUT: BLOCK")
|
return nil
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if _, ok := chanMessage.Resource.(*Transaction); ok {
|
|
||||||
log.Println("BREAKING OUT: TX")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
i++
|
i++
|
||||||
if i%1234567 == 0 {
|
if i%1234567 == 0 {
|
||||||
|
@ -50,9 +50,6 @@ type StateManager struct {
|
|||||||
// Comparative state it used for comparing and validating end
|
// Comparative state it used for comparing and validating end
|
||||||
// results
|
// results
|
||||||
compState *State
|
compState *State
|
||||||
|
|
||||||
// Mining state, solely used for mining
|
|
||||||
miningState *State
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStateManager(ethereum EthManager) *StateManager {
|
func NewStateManager(ethereum EthManager) *StateManager {
|
||||||
@ -65,7 +62,6 @@ func NewStateManager(ethereum EthManager) *StateManager {
|
|||||||
bc: ethereum.BlockChain(),
|
bc: ethereum.BlockChain(),
|
||||||
}
|
}
|
||||||
sm.procState = ethereum.BlockChain().CurrentBlock.State()
|
sm.procState = ethereum.BlockChain().CurrentBlock.State()
|
||||||
|
|
||||||
return sm
|
return sm
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,10 +69,6 @@ func (sm *StateManager) ProcState() *State {
|
|||||||
return sm.procState
|
return sm.procState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) MiningState() *State {
|
|
||||||
return sm.miningState
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watches any given address and puts it in the address state store
|
// Watches any given address and puts it in the address state store
|
||||||
func (sm *StateManager) WatchAddr(addr []byte) *AccountState {
|
func (sm *StateManager) WatchAddr(addr []byte) *AccountState {
|
||||||
//XXX account := sm.bc.CurrentBlock.state.GetAccount(addr)
|
//XXX account := sm.bc.CurrentBlock.state.GetAccount(addr)
|
||||||
@ -105,8 +97,6 @@ func (sm *StateManager) MakeContract(tx *Transaction) {
|
|||||||
sm.procState.states[string(tx.Hash()[12:])] = contract.state
|
sm.procState.states[string(tx.Hash()[12:])] = contract.state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (sm *StateManager) ApplyTransaction(block *Block, tx *Transaction) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
|
func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
|
||||||
// Process each transaction/contract
|
// Process each transaction/contract
|
||||||
@ -136,17 +126,13 @@ func (sm *StateManager) Prepare(processer *State, comparative *State) {
|
|||||||
sm.procState = processer
|
sm.procState = processer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) PrepareMiningState() {
|
|
||||||
sm.miningState = sm.BlockChain().CurrentBlock.State()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default prepare function
|
// Default prepare function
|
||||||
func (sm *StateManager) PrepareDefault(block *Block) {
|
func (sm *StateManager) PrepareDefault(block *Block) {
|
||||||
sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State())
|
sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block processing and validating with a given (temporarily) state
|
// Block processing and validating with a given (temporarily) state
|
||||||
func (sm *StateManager) ProcessBlock(block *Block) error {
|
func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
|
||||||
// Processing a blocks may never happen simultaneously
|
// Processing a blocks may never happen simultaneously
|
||||||
sm.mutex.Lock()
|
sm.mutex.Lock()
|
||||||
defer sm.mutex.Unlock()
|
defer sm.mutex.Unlock()
|
||||||
@ -155,7 +141,6 @@ func (sm *StateManager) ProcessBlock(block *Block) error {
|
|||||||
// nodes this won't happen because Commit would have been called
|
// nodes this won't happen because Commit would have been called
|
||||||
// before that.
|
// before that.
|
||||||
defer sm.bc.CurrentBlock.Undo()
|
defer sm.bc.CurrentBlock.Undo()
|
||||||
|
|
||||||
hash := block.Hash()
|
hash := block.Hash()
|
||||||
|
|
||||||
if sm.bc.HasBlock(hash) {
|
if sm.bc.HasBlock(hash) {
|
||||||
@ -207,7 +192,9 @@ func (sm *StateManager) ProcessBlock(block *Block) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash())
|
ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash())
|
||||||
sm.Ethereum.Reactor().Post("newBlock", block)
|
if dontReact == false {
|
||||||
|
sm.Ethereum.Reactor().Post("newBlock", block)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("total diff failed")
|
fmt.Println("total diff failed")
|
||||||
}
|
}
|
||||||
@ -285,15 +272,16 @@ func CalculateUncleReward(block *Block) *big.Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) AccumelateRewards(block *Block) error {
|
func (sm *StateManager) AccumelateRewards(block *Block) error {
|
||||||
|
|
||||||
// Get the coinbase rlp data
|
// Get the coinbase rlp data
|
||||||
//XXX addr := processor.state.GetAccount(block.Coinbase)
|
//XXX addr := processor.state.GetAccount(block.Coinbase)
|
||||||
addr := sm.procState.GetAccount(block.Coinbase)
|
addr := sm.procState.GetAccount(block.Coinbase)
|
||||||
// Reward amount of ether to the coinbase address
|
// Reward amount of ether to the coinbase address
|
||||||
addr.AddFee(CalculateBlockReward(block, len(block.Uncles)))
|
addr.AddFee(CalculateBlockReward(block, len(block.Uncles)))
|
||||||
|
|
||||||
//XXX processor.state.UpdateAccount(block.Coinbase, addr)
|
//XXX processor.state.UpdateAccount(block.Coinbase, addr)
|
||||||
sm.procState.UpdateAccount(block.Coinbase, addr)
|
var acc []byte
|
||||||
|
copy(acc, block.Coinbase)
|
||||||
|
sm.procState.UpdateAccount(acc, addr)
|
||||||
for _, uncle := range block.Uncles {
|
for _, uncle := range block.Uncles {
|
||||||
uncleAddr := sm.procState.GetAccount(uncle.Coinbase)
|
uncleAddr := sm.procState.GetAccount(uncle.Coinbase)
|
||||||
uncleAddr.AddFee(CalculateUncleReward(uncle))
|
uncleAddr.AddFee(CalculateUncleReward(uncle))
|
||||||
|
@ -91,7 +91,6 @@ func (pool *TxPool) addTransaction(tx *Transaction) {
|
|||||||
// Process transaction validates the Tx and processes funds from the
|
// Process transaction validates the Tx and processes funds from the
|
||||||
// sender to the recipient.
|
// sender to the recipient.
|
||||||
func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) {
|
func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error) {
|
||||||
log.Println("Processing TX")
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
log.Println(r)
|
log.Println(r)
|
||||||
@ -105,11 +104,11 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block) (err error
|
|||||||
// funds won't invalidate this transaction but simple ignores it.
|
// funds won't invalidate this transaction but simple ignores it.
|
||||||
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
|
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
|
||||||
if sender.Amount.Cmp(totAmount) < 0 {
|
if sender.Amount.Cmp(totAmount) < 0 {
|
||||||
return errors.New("Insufficient amount in sender's account")
|
return errors.New("[TXPL] Insufficient amount in sender's account")
|
||||||
}
|
}
|
||||||
|
|
||||||
if sender.Nonce != tx.Nonce {
|
if sender.Nonce != tx.Nonce {
|
||||||
return fmt.Errorf("Invalid nonce %d(%d)", tx.Nonce, sender.Nonce)
|
return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transactoin nonce is %d instead", sender.Nonce, tx.Nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the receiver
|
// Get the receiver
|
||||||
@ -145,7 +144,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
|
|||||||
block := pool.Ethereum.BlockChain().CurrentBlock
|
block := pool.Ethereum.BlockChain().CurrentBlock
|
||||||
// Something has gone horribly wrong if this happens
|
// Something has gone horribly wrong if this happens
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return errors.New("No last block on the block chain")
|
return errors.New("[TXPL] No last block on the block chain")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the sender
|
// Get the sender
|
||||||
@ -156,7 +155,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
|
|||||||
// Make sure there's enough in the sender's account. Having insufficient
|
// Make sure there's enough in the sender's account. Having insufficient
|
||||||
// funds won't invalidate this transaction but simple ignores it.
|
// funds won't invalidate this transaction but simple ignores it.
|
||||||
if sender.Amount.Cmp(totAmount) < 0 {
|
if sender.Amount.Cmp(totAmount) < 0 {
|
||||||
return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender())
|
return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment the nonce making each tx valid only once to prevent replay
|
// Increment the nonce making each tx valid only once to prevent replay
|
||||||
|
149
ethminer/miner.go
Normal file
149
ethminer/miner.go
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package ethminer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/ethereum/eth-go/ethchain"
|
||||||
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
|
"github.com/ethereum/eth-go/ethwire"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Miner struct {
|
||||||
|
pow ethchain.PoW
|
||||||
|
ethereum ethchain.EthManager
|
||||||
|
coinbase []byte
|
||||||
|
reactChan chan ethutil.React
|
||||||
|
txs []*ethchain.Transaction
|
||||||
|
uncles []*ethchain.Block
|
||||||
|
block *ethchain.Block
|
||||||
|
powChan chan []byte
|
||||||
|
quitChan chan ethutil.React
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
|
||||||
|
reactChan := make(chan ethutil.React, 1) // This is the channel that receives 'updates' when ever a new transaction or block comes in
|
||||||
|
powChan := make(chan []byte, 1) // This is the channel that receives valid sha hases for a given block
|
||||||
|
quitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread
|
||||||
|
|
||||||
|
ethereum.Reactor().Subscribe("newBlock", reactChan)
|
||||||
|
ethereum.Reactor().Subscribe("newTx", reactChan)
|
||||||
|
|
||||||
|
// We need the quit chan to be a Reactor event.
|
||||||
|
// The POW search method is actually blocking and if we don't
|
||||||
|
// listen to the reactor events inside of the pow itself
|
||||||
|
// The miner overseer will never get the reactor events themselves
|
||||||
|
// Only after the miner will find the sha
|
||||||
|
ethereum.Reactor().Subscribe("newBlock", quitChan)
|
||||||
|
ethereum.Reactor().Subscribe("newTx", quitChan)
|
||||||
|
|
||||||
|
miner := Miner{
|
||||||
|
pow: ðchain.EasyPow{},
|
||||||
|
ethereum: ethereum,
|
||||||
|
coinbase: coinbase,
|
||||||
|
reactChan: reactChan,
|
||||||
|
powChan: powChan,
|
||||||
|
quitChan: quitChan,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert initial TXs in our little miner 'pool'
|
||||||
|
miner.txs = ethereum.TxPool().Flush()
|
||||||
|
miner.block = ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
|
||||||
|
|
||||||
|
return miner
|
||||||
|
}
|
||||||
|
func (miner *Miner) Start() {
|
||||||
|
// Prepare inital block
|
||||||
|
miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
|
||||||
|
go func() { miner.listener() }()
|
||||||
|
}
|
||||||
|
func (miner *Miner) listener() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case chanMessage := <-miner.reactChan:
|
||||||
|
if block, ok := chanMessage.Resource.(*ethchain.Block); ok {
|
||||||
|
log.Println("[miner] Got new block via Reactor")
|
||||||
|
if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 {
|
||||||
|
// TODO: Perhaps continue mining to get some uncle rewards
|
||||||
|
log.Println("[miner] New top block found resetting state")
|
||||||
|
|
||||||
|
// Filter out which Transactions we have that were not in this block
|
||||||
|
var newtxs []*ethchain.Transaction
|
||||||
|
for _, tx := range miner.txs {
|
||||||
|
found := false
|
||||||
|
for _, othertx := range block.Transactions() {
|
||||||
|
if bytes.Compare(tx.Hash(), othertx.Hash()) == 0 {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found == false {
|
||||||
|
newtxs = append(newtxs, tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
miner.txs = newtxs
|
||||||
|
|
||||||
|
// Setup a fresh state to mine on
|
||||||
|
miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 {
|
||||||
|
log.Println("[miner] Adding uncle block")
|
||||||
|
miner.uncles = append(miner.uncles, block)
|
||||||
|
miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok {
|
||||||
|
log.Println("[miner] Got new transaction from Reactor", tx)
|
||||||
|
found := false
|
||||||
|
for _, ctx := range miner.txs {
|
||||||
|
if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if found == false {
|
||||||
|
log.Println("[miner] We did not know about this transaction, adding")
|
||||||
|
miner.txs = append(miner.txs, tx)
|
||||||
|
miner.block.SetTransactions(miner.txs)
|
||||||
|
} else {
|
||||||
|
log.Println("[miner] We already had this transaction, ignoring")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Println("[miner] Mining on block. Includes", len(miner.txs), "transactions")
|
||||||
|
|
||||||
|
// Apply uncles
|
||||||
|
if len(miner.uncles) > 0 {
|
||||||
|
miner.block.SetUncles(miner.uncles)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply all transactions to the block
|
||||||
|
miner.ethereum.StateManager().ApplyTransactions(miner.block, miner.block.Transactions())
|
||||||
|
miner.ethereum.StateManager().AccumelateRewards(miner.block)
|
||||||
|
|
||||||
|
// Search the nonce
|
||||||
|
log.Println("[miner] Initialision complete, starting mining")
|
||||||
|
miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan)
|
||||||
|
if miner.block.Nonce != nil {
|
||||||
|
miner.ethereum.StateManager().PrepareDefault(miner.block)
|
||||||
|
err := miner.ethereum.StateManager().ProcessBlock(miner.block, true)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error result from process block:", err)
|
||||||
|
log.Println(miner.block)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) {
|
||||||
|
log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce))
|
||||||
|
}
|
||||||
|
miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val})
|
||||||
|
log.Printf("[miner] 🔨 Mined block %x\n", miner.block.Hash())
|
||||||
|
log.Println(miner.block)
|
||||||
|
|
||||||
|
miner.txs = []*ethchain.Transaction{} // Move this somewhere neat
|
||||||
|
miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
peer.go
2
peer.go
@ -295,7 +295,7 @@ func (p *Peer) HandleInbound() {
|
|||||||
block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i))
|
block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i))
|
||||||
|
|
||||||
p.ethereum.StateManager().PrepareDefault(block)
|
p.ethereum.StateManager().PrepareDefault(block)
|
||||||
err = p.ethereum.StateManager().ProcessBlock(block)
|
err = p.ethereum.StateManager().ProcessBlock(block, true)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ethutil.Config.Debug {
|
if ethutil.Config.Debug {
|
||||||
|
Loading…
Reference in New Issue
Block a user