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