You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
8.8 KiB

  1. // Copyright 2017-2018 DERO Project. All rights reserved.
  2. // Use of this source code in any form is governed by RESEARCH license.
  3. // license can be found in the LICENSE file.
  4. // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
  5. //
  6. //
  7. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
  8. // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  10. // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  11. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  12. // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  13. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  14. // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  15. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. package block
  17. import "fmt"
  18. import "bytes"
  19. import "encoding/hex"
  20. import "encoding/binary"
  21. import "github.com/romana/rlog"
  22. import "github.com/deroproject/derosuite/crypto"
  23. import "github.com/deroproject/derosuite/config"
  24. import "github.com/deroproject/derosuite/cryptonight"
  25. import "github.com/deroproject/derosuite/transaction"
  26. // these are defined in file
  27. //https://github.com/monero-project/monero/src/cryptonote_basic/cryptonote_basic.h
  28. type Block_Header struct {
  29. Major_Version uint32 `json:"major_version"`
  30. Minor_Version uint32 `json:"minor_version"`
  31. Timestamp uint64 `json:"timestamp"`
  32. Prev_Hash crypto.Hash `json:"prev_id"`
  33. Nonce uint32 `json:"nonce"`
  34. }
  35. type Block struct {
  36. Block_Header
  37. Miner_tx transaction.Transaction `json:"miner_tx"`
  38. Merkle_Root crypto.Hash `json:"-"`
  39. Tx_hashes []crypto.Hash `json:"tx_hashes"`
  40. treehash crypto.Hash
  41. }
  42. // we process incoming blocks in this format
  43. type Complete_Block struct {
  44. Bl *Block
  45. Txs []*transaction.Transaction
  46. }
  47. // see spec here https://cryptonote.org/cns/cns003.txt
  48. // this function gets the block identifier hash
  49. func (bl *Block) GetHash() (hash crypto.Hash) {
  50. buf := make([]byte, binary.MaxVarintLen64)
  51. long_header := bl.GetBlockWork()
  52. length := uint64(len(long_header))
  53. n := binary.PutUvarint(buf, length) //
  54. buf = buf[:n]
  55. block_id_blob := append(buf, long_header...)
  56. // keccak hash of this above blob, gives the block id
  57. hash2 := crypto.Keccak256(block_id_blob)
  58. return crypto.Hash(hash2)
  59. }
  60. // converts a block, into a getwork style work, ready for either submitting the block
  61. // or doing Pow Calculations
  62. func (bl *Block) GetBlockWork() []byte {
  63. buf := make([]byte, binary.MaxVarintLen64)
  64. header := bl.SerializeHeader()
  65. tx_treehash := bl.GetTreeHash() // treehash of all transactions
  66. // length of all transactions
  67. n := binary.PutUvarint(buf, uint64(len(bl.Tx_hashes)+1)) // +1 for miner TX
  68. buf = buf[:n]
  69. long_header := append(header, tx_treehash[:]...)
  70. long_header = append(long_header, buf...)
  71. return long_header
  72. }
  73. // Get PoW hash , this is very slow function
  74. func (bl *Block) GetPoWHash() (hash crypto.Hash) {
  75. long_header := bl.GetBlockWork()
  76. rlog.Tracef(9, "longheader %x\n", long_header)
  77. tmphash := cryptonight.SlowHash(long_header)
  78. copy(hash[:], tmphash[:32])
  79. return
  80. }
  81. // Reward is, total amount in the miner tx - fees
  82. func (bl *Block) GetReward() uint64 {
  83. total_amount := bl.Miner_tx.Vout[0].Amount
  84. total_fees := uint64(0)
  85. // load all the TX and get the fees, since we are in a post rct world
  86. // extract the fees from the rct sig
  87. return total_amount - total_fees
  88. }
  89. // serialize block header
  90. func (bl *Block) SerializeHeader() []byte {
  91. var serialised bytes.Buffer
  92. buf := make([]byte, binary.MaxVarintLen64)
  93. n := binary.PutUvarint(buf, uint64(bl.Major_Version))
  94. serialised.Write(buf[:n])
  95. n = binary.PutUvarint(buf, uint64(bl.Minor_Version))
  96. serialised.Write(buf[:n])
  97. n = binary.PutUvarint(buf, bl.Timestamp)
  98. serialised.Write(buf[:n])
  99. serialised.Write(bl.Prev_Hash[:32]) // write previous ID
  100. binary.LittleEndian.PutUint32(buf[0:8], bl.Nonce) // check whether it needs to be big endian
  101. serialised.Write(buf[:4])
  102. return serialised.Bytes()
  103. }
  104. // serialize entire block ( block_header + miner_tx + tx_list )
  105. func (bl *Block) Serialize() []byte {
  106. var serialized bytes.Buffer
  107. buf := make([]byte, binary.MaxVarintLen64)
  108. header := bl.SerializeHeader()
  109. serialized.Write(header)
  110. // miner tx should always be coinbase
  111. minex_tx := bl.Miner_tx.Serialize()
  112. serialized.Write(minex_tx)
  113. //fmt.Printf("serializing tx hashes %d\n", len(bl.Tx_hashes))
  114. n := binary.PutUvarint(buf, uint64(len(bl.Tx_hashes)))
  115. serialized.Write(buf[:n])
  116. for _, hash := range bl.Tx_hashes {
  117. serialized.Write(hash[:])
  118. }
  119. return serialized.Bytes()
  120. }
  121. // get block transactions tree hash
  122. func (bl *Block) GetTreeHash() (hash crypto.Hash) {
  123. var hash_list []crypto.Hash
  124. hash_list = append(hash_list, bl.Miner_tx.GetHash())
  125. // add all the remaining hashes
  126. for i := range bl.Tx_hashes {
  127. hash_list = append(hash_list, bl.Tx_hashes[i])
  128. }
  129. return TreeHash(hash_list)
  130. }
  131. // input is the list of transactions hashes
  132. func TreeHash(hashes []crypto.Hash) (hash crypto.Hash) {
  133. switch len(hashes) {
  134. case 0:
  135. panic("Treehash cannot have 0 transactions, atleast miner tx will be present")
  136. case 1:
  137. copy(hash[:], hashes[0][:32])
  138. case 2:
  139. var buf []byte
  140. for i := 0; i < len(hashes); i++ {
  141. buf = append(buf, hashes[i][:32]...)
  142. }
  143. tmp_hash := crypto.Keccak256(buf)
  144. copy(hash[:], tmp_hash[:32])
  145. default:
  146. count := uint64(len(hashes))
  147. cnt := tree_hash_cnt(count)
  148. //fmt.Printf("cnt %d count %d\n",cnt, count)
  149. ints := make([]byte, 32*cnt, 32*cnt)
  150. hashes_buf := make([]byte, 32*count, 32*count)
  151. for i := uint64(0); i < count; i++ {
  152. copy(hashes_buf[i*32:], hashes[i][:32]) // copy hashes 1 by 1
  153. }
  154. for i := uint64(0); i < ((2 * cnt) - count); i++ {
  155. copy(ints[i*32:], hashes[i][:32]) // copy hashes 1 by 1
  156. }
  157. i := ((2 * cnt) - count)
  158. j := ((2 * cnt) - count)
  159. for ; j < cnt; i, j = i+2, j+1 {
  160. hash := crypto.Keccak256(hashes_buf[i*32 : (i*32)+64]) // find hash of 64 bytes
  161. copy(ints[j*32:], hash[:32])
  162. }
  163. if i != count {
  164. panic("please fix tree hash")
  165. }
  166. for cnt > 2 {
  167. cnt = cnt >> 1
  168. i = 0
  169. j = 0
  170. for ; j < cnt; i, j = i+2, j+1 {
  171. hash := crypto.Keccak256(ints[i*32 : (i*32)+64]) // find hash of 64 bytes
  172. copy(ints[j*32:], hash[:32])
  173. }
  174. }
  175. hash = crypto.Hash(crypto.Keccak256(ints[0:64])) // find hash of 64 bytes
  176. }
  177. return
  178. }
  179. // see crypto/tree-hash.c
  180. // this function has a naughty history
  181. func tree_hash_cnt(count uint64) uint64 {
  182. pow := uint64(2)
  183. for pow < count {
  184. pow = pow << 1
  185. }
  186. return pow >> 1
  187. }
  188. func (bl *Block) Deserialize(buf []byte) (err error) {
  189. done := 0
  190. var tmp uint64
  191. defer func() {
  192. if r := recover(); r != nil {
  193. fmt.Printf("Panic while deserialising block, block hex_dump below to make a testcase/debug\n")
  194. fmt.Printf("%s", hex.EncodeToString(buf))
  195. err = fmt.Errorf("Invalid Block")
  196. return
  197. }
  198. }()
  199. tmp, done = binary.Uvarint(buf)
  200. if done <= 0 {
  201. return fmt.Errorf("Invalid Version in Block\n")
  202. }
  203. buf = buf[done:]
  204. bl.Major_Version = uint32(tmp)
  205. if uint64(bl.Major_Version) != tmp {
  206. return fmt.Errorf("Invalid Block major version")
  207. }
  208. tmp, done = binary.Uvarint(buf)
  209. if done <= 0 {
  210. return fmt.Errorf("Invalid minor Version in Block\n")
  211. }
  212. buf = buf[done:]
  213. bl.Minor_Version = uint32(tmp)
  214. if uint64(bl.Minor_Version) != tmp {
  215. return fmt.Errorf("Invalid Block minor version")
  216. }
  217. bl.Timestamp, done = binary.Uvarint(buf)
  218. if done <= 0 {
  219. return fmt.Errorf("Invalid Timestamp in Block\n")
  220. }
  221. buf = buf[done:]
  222. copy(bl.Prev_Hash[:], buf[:32]) // hash is always 32 byte
  223. buf = buf[32:]
  224. bl.Nonce = binary.LittleEndian.Uint32(buf)
  225. buf = buf[4:] // nonce is always 4 bytes
  226. // read and parse transaction
  227. err = bl.Miner_tx.DeserializeHeader(buf)
  228. if err != nil {
  229. return fmt.Errorf("Cannot parse miner TX %x", buf)
  230. }
  231. // if tx was parse, make sure it's coin base
  232. if len(bl.Miner_tx.Vin) != 1 || bl.Miner_tx.Vin[0].(transaction.Txin_gen).Height > config.MAX_CHAIN_HEIGHT {
  233. // serialize transaction again to get the tx size, so as parsing could continue
  234. return fmt.Errorf("Invalid Miner TX")
  235. }
  236. miner_tx_serialized_size := bl.Miner_tx.Serialize()
  237. buf = buf[len(miner_tx_serialized_size):]
  238. //fmt.Printf("miner tx %x\n", miner_tx_serialized_size)
  239. // read number of transactions
  240. tx_count, done := binary.Uvarint(buf)
  241. if done <= 0 {
  242. return fmt.Errorf("Invalid Tx count in Block\n")
  243. }
  244. buf = buf[done:]
  245. // remember first tx is merkle root
  246. for i := uint64(0); i < tx_count; i++ {
  247. //fmt.Printf("Parsing transaction hash %d tx_count %d\n", i, tx_count)
  248. var h crypto.Hash
  249. copy(h[:], buf[:32])
  250. buf = buf[32:]
  251. bl.Tx_hashes = append(bl.Tx_hashes, h)
  252. }
  253. //fmt.Printf("%d member in tx hashes \n",len(bl.Tx_hashes))
  254. return
  255. }