tpl.go raw

   1  package templates
   2  
   3  import (
   4  	"errors"
   5  	"time"
   6  
   7  	"github.com/niubaoshu/gotiny"
   8  
   9  	"github.com/p9c/p9/pkg/chainhash"
  10  	"github.com/p9c/p9/pkg/wire"
  11  )
  12  
  13  type (
  14  	// Diffs is a bundle of difficulty bits
  15  	Diffs map[int32]uint32
  16  	// Merkles is a bundle of merkle roots
  17  	Merkles map[int32]chainhash.Hash
  18  	// Txs is a set of transactions
  19  	Txs map[int32][]*wire.MsgTx
  20  )
  21  
  22  // Message describes a message that a mining worker can use to construct a block
  23  // to mine on, as well the extra data required to reconstruct any version block
  24  // mined by the miner
  25  type Message struct {
  26  	Nonce     uint64
  27  	UUID      uint64
  28  	Height    int32
  29  	PrevBlock chainhash.Hash
  30  	Bits      Diffs
  31  	Merkles   Merkles
  32  	txs       Txs
  33  	Timestamp time.Time
  34  }
  35  
  36  // SetTxs writes to the private, non-serialized transactions field
  37  func (m *Message) SetTxs(ver int32, txs []*wire.MsgTx) {
  38  	if m.txs == nil {
  39  		m.txs = make(Txs)
  40  	}
  41  	m.txs[ver] = txs
  42  }
  43  
  44  // GetTxs returns the transactions
  45  func (m *Message) GetTxs() (txs map[int32][]*wire.MsgTx) {
  46  	return m.txs
  47  }
  48  
  49  // Serialize the Message for the wire
  50  func (m *Message) Serialize() []byte {
  51  	return gotiny.Marshal(m)
  52  }
  53  
  54  // DeserializeMsgBlockTemplate takes a message expected to be a Message
  55  // and reconstitutes it
  56  func DeserializeMsgBlockTemplate(b []byte) (m *Message) {
  57  	m = &Message{}
  58  	gotiny.Unmarshal(b, m)
  59  	return
  60  }
  61  
  62  // GenBlockHeader generate a block given a version number to use for mining
  63  // The nonce is empty, date can be updated, version changes merkle and target bits.
  64  // All the data required for this is in the exported fields that are serialized
  65  // for over the wire
  66  func (m *Message) GenBlockHeader(vers int32) *wire.BlockHeader {
  67  	return &wire.BlockHeader{
  68  		Version:    vers,
  69  		PrevBlock:  m.PrevBlock,
  70  		MerkleRoot: m.Merkles[vers],
  71  		Timestamp:  m.Timestamp,
  72  		Bits:       m.Bits[vers],
  73  	}
  74  }
  75  
  76  // Reconstruct takes a received block from the wire and reattaches the transactions
  77  func (m *Message) Reconstruct(hdr *wire.BlockHeader) (mb *wire.Block, e error) {
  78  	if hdr.PrevBlock != m.PrevBlock {
  79  		e = errors.New("block is not for same parent block")
  80  		return
  81  	}
  82  	mb = &wire.Block{Header: *hdr, Transactions: m.txs[hdr.Version]}
  83  	return
  84  }
  85  
  86  // RecentMessages keeps a buffer of four previously created messages so that
  87  // solutions found after a new template is created can be submitted
  88  type RecentMessages struct {
  89  	msgs   [4]*Message
  90  	cursor int
  91  }
  92  
  93  func NewRecentMessages() *RecentMessages {
  94  	return &RecentMessages{
  95  		msgs:   [4]*Message{},
  96  		cursor: 0,
  97  	}
  98  }
  99  
 100  // Add a message to the RecentMessages, we just write to the current cursor
 101  // position, and then advance it, back to zero if it exceeds the buffer length,
 102  // overwriting the first, and so on
 103  func (rm *RecentMessages) Add(msg *Message) {
 104  	D.Ln("adding template with cursor", rm.cursor)
 105  	rm.msgs[rm.cursor] = msg
 106  	rm.cursor++
 107  	if rm.cursor >= 4 {
 108  		rm.cursor = 0
 109  	}
 110  }
 111  
 112  // Len returns the number of elements in the buffer
 113  func (rm *RecentMessages) Len() (o int) {
 114  	for i := range rm.msgs {
 115  		if rm.msgs[i] != nil {
 116  			o++
 117  		}
 118  	}
 119  	return
 120  }
 121  
 122  // Find checks whether the given nonce matches any of the cached Message's and remove it from the list
 123  func (rm *RecentMessages) Find(nonce uint64) *Message {
 124  	for i := range rm.msgs {
 125  		if rm.msgs[i] != nil {
 126  			I.Ln("recent message", i, rm.msgs[i].Nonce, nonce)
 127  			if rm.msgs[i].Nonce == nonce {
 128  				I.Ln("found message", nonce)
 129  				msg := rm.msgs[i]
 130  				rm.msgs[i] = nil
 131  				rm.cursor = i
 132  				return msg
 133  			}
 134  		}
 135  	}
 136  	return nil
 137  }
 138