github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/block/block.go (about) 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 17 package block 18 19 import "fmt" 20 21 //import "sort" 22 import "bytes" 23 import "runtime/debug" 24 import "encoding/hex" 25 import "encoding/binary" 26 27 import "github.com/ebfe/keccak" 28 import "github.com/romana/rlog" 29 30 import "github.com/deroproject/derosuite/crypto" 31 32 //import "github.com/deroproject/derosuite/config" 33 import "github.com/deroproject/derosuite/astrobwt" 34 import "github.com/deroproject/derosuite/cryptonight" 35 import "github.com/deroproject/derosuite/transaction" 36 37 // these are defined in file 38 //https://github.com/monero-project/monero/src/cryptonote_basic/cryptonote_basic.h 39 type Block_Header struct { 40 Major_Version uint64 `json:"major_version"` 41 Minor_Version uint64 `json:"minor_version"` 42 Timestamp uint64 `json:"timestamp"` 43 Nonce uint32 `json:"nonce"` // TODO make nonce 32 byte array for infinite work capacity 44 ExtraNonce [32]byte `json:"-"` 45 Miner_TX transaction.Transaction `json:"miner_tx"` 46 } 47 48 type Block struct { 49 Block_Header 50 Proof [32]byte `json:"-"` // Reserved for future 51 Tips []crypto.Hash `json:"tips"` 52 Tx_hashes []crypto.Hash `json:"tx_hashes"` 53 } 54 55 // we process incoming blocks in this format 56 type Complete_Block struct { 57 Bl *Block 58 Txs []*transaction.Transaction 59 } 60 61 // see spec here https://cryptonote.org/cns/cns003.txt 62 // this function gets the block identifier hash 63 // this has been simplified and varint length has been removed 64 func (bl *Block) GetHash() (hash crypto.Hash) { 65 long_header := bl.GetBlockWork() 66 67 // keccak hash of this above blob, gives the block id 68 return crypto.Keccak256(long_header) 69 } 70 71 // converts a block, into a getwork style work, ready for either submitting the block 72 // or doing Pow Calculations 73 func (bl *Block) GetBlockWork() []byte { 74 75 var buf []byte // bitcoin/litecoin getworks are 80 bytes 76 var scratch [8]byte 77 78 buf = append(buf, []byte{byte(bl.Major_Version), byte(bl.Minor_Version), 0, 0, 0, 0, 0}...) // 0 first 7 bytes are version in little endia format 79 80 binary.LittleEndian.PutUint32(buf[2:6], uint32(bl.Timestamp)) 81 header_hash := crypto.Keccak256(bl.getserializedheaderforwork()) // 0 + 7 82 83 buf = append(buf, header_hash[:]...) // 0 + 7 + 32 = 39 84 85 binary.LittleEndian.PutUint32(scratch[0:4], bl.Nonce) // check whether it needs to be big endian 86 buf = append(buf, scratch[:4]...) // 0 + 7 + 32 + 4 = 43 87 88 // next place the ExtraNonce 89 buf = append(buf, bl.ExtraNonce[:]...) // total 7 + 32 + 4 + 32 90 91 buf = append(buf, 0) // total 7 + 32 + 4 + 32 + 1 = 76 92 93 if len(buf) != 76 { 94 panic(fmt.Sprintf("Getwork not equal to 76 bytes actual %d", len(buf))) 95 96 } 97 return buf 98 } 99 100 // copy the nonce and the extra nonce from the getwork to the block 101 func (bl *Block) CopyNonceFromBlockWork(work []byte) (err error) { 102 if len(work) < 74 { 103 return fmt.Errorf("work buffer is Invalid") 104 } 105 106 bl.Timestamp = uint64(binary.LittleEndian.Uint32(work[2:])) 107 bl.Nonce = binary.LittleEndian.Uint32(work[7+32:]) 108 copy(bl.ExtraNonce[:], work[7+32+4:75]) 109 return 110 } 111 112 // copy the nonce and the extra nonce from the getwork to the block 113 func (bl *Block) SetExtraNonce(extranonce []byte) (err error) { 114 115 if len(extranonce) == 0 { 116 return fmt.Errorf("extra nonce is invalid") 117 } 118 max := len(extranonce) 119 if max > 32 { 120 max = 32 121 } 122 copy(bl.ExtraNonce[:], extranonce[0:max]) 123 return 124 } 125 126 // clear extra nonce 127 func (bl *Block) ClearExtraNonce() { 128 for i := range bl.ExtraNonce { 129 bl.ExtraNonce[i] = 0 130 } 131 } 132 133 // clear nonce 134 func (bl *Block) ClearNonce() { 135 bl.Nonce = 0 136 } 137 138 // Get PoW hash , this is very slow function 139 func (bl *Block) GetPoWHash() (hash crypto.Hash) { 140 long_header := bl.GetBlockWork() 141 rlog.Tracef(9, "longheader %x\n", long_header) 142 143 if bl.Major_Version <=3 { // HF 1 to 3 use crypto night 144 tmphash := cryptonight.SlowHash(long_header) 145 copy(hash[:], tmphash[:32]) 146 }else{ 147 tmphash := astrobwt.POW_0alloc(long_header) // new astrobwt algorithm 148 copy(hash[:], tmphash[:32]) 149 } 150 151 return 152 } 153 154 // serialize block header for calculating PoW 155 func (bl *Block) getserializedheaderforwork() []byte { 156 var serialised bytes.Buffer 157 158 buf := make([]byte, binary.MaxVarintLen64) 159 160 n := binary.PutUvarint(buf, uint64(bl.Major_Version)) 161 serialised.Write(buf[:n]) 162 163 n = binary.PutUvarint(buf, uint64(bl.Minor_Version)) 164 serialised.Write(buf[:n]) 165 166 // it is placed in pow 167 //n = binary.PutUvarint(buf, bl.Timestamp) 168 //serialised.Write(buf[:n]) 169 170 // write miner tx 171 serialised.Write(bl.Miner_TX.Serialize()) 172 173 // write tips,, merkle tree should be replaced with something faster 174 tips_treehash := bl.GetTipsHash() 175 n = binary.PutUvarint(buf, uint64(len(tips_treehash))) 176 serialised.Write(buf[:n]) 177 serialised.Write(tips_treehash[:]) // actual tips hash 178 179 tx_treehash := bl.GetTXSHash() // hash of all transactions 180 n = binary.PutUvarint(buf, uint64(len(bl.Tx_hashes))) // count of all transactions 181 serialised.Write(buf[:n]) 182 serialised.Write(tx_treehash[:]) // actual transactions hash 183 184 return serialised.Bytes() 185 } 186 187 // serialize block header 188 func (bl *Block) SerializeHeader() []byte { 189 190 var serialised bytes.Buffer 191 192 buf := make([]byte, binary.MaxVarintLen64) 193 194 n := binary.PutUvarint(buf, uint64(bl.Major_Version)) 195 serialised.Write(buf[:n]) 196 197 n = binary.PutUvarint(buf, uint64(bl.Minor_Version)) 198 serialised.Write(buf[:n]) 199 200 n = binary.PutUvarint(buf, bl.Timestamp) 201 serialised.Write(buf[:n]) 202 203 binary.LittleEndian.PutUint32(buf[0:8], bl.Nonce) // check whether it needs to be big endian 204 serialised.Write(buf[:4]) 205 206 serialised.Write(bl.ExtraNonce[:]) 207 208 // write miner address 209 serialised.Write(bl.Miner_TX.Serialize()) 210 211 return serialised.Bytes() 212 213 } 214 215 // serialize entire block ( block_header + miner_tx + tx_list ) 216 func (bl *Block) Serialize() []byte { 217 var serialized bytes.Buffer 218 buf := make([]byte, binary.MaxVarintLen64) 219 220 header := bl.SerializeHeader() 221 serialized.Write(header) 222 223 serialized.Write(bl.Proof[:]) // write proof NOT implemented 224 225 // miner tx should always be coinbase 226 //minex_tx := bl.Miner_tx.Serialize() 227 //serialized.Write(minex_tx) 228 229 n := binary.PutUvarint(buf, uint64(len(bl.Tips))) 230 serialized.Write(buf[:n]) 231 232 for _, hash := range bl.Tips { 233 serialized.Write(hash[:]) 234 } 235 236 //fmt.Printf("serializing tx hashes %d\n", len(bl.Tx_hashes)) 237 238 n = binary.PutUvarint(buf, uint64(len(bl.Tx_hashes))) 239 serialized.Write(buf[:n]) 240 241 for _, hash := range bl.Tx_hashes { 242 serialized.Write(hash[:]) 243 } 244 245 return serialized.Bytes() 246 } 247 248 // get block transactions tree hash 249 func (bl *Block) GetTipsHash() (result crypto.Hash) { 250 251 /*if len(bl.Tips) == 0 { // case for genesis block 252 panic("Block does NOT refer any tips") 253 }*/ 254 255 // add all the remaining hashes 256 h := keccak.New256() 257 for i := range bl.Tips { 258 h.Write(bl.Tips[i][:]) 259 } 260 r := h.Sum(nil) 261 copy(result[:], r) 262 return 263 } 264 265 // get block transactions 266 // we have discarded the merkle tree and have shifted to a plain version 267 func (bl *Block) GetTXSHash() (result crypto.Hash) { 268 h := keccak.New256() 269 for i := range bl.Tx_hashes { 270 h.Write(bl.Tx_hashes[i][:]) 271 } 272 r := h.Sum(nil) 273 copy(result[:], r) 274 275 return 276 } 277 278 // only parses header 279 func (bl *Block) DeserializeHeader(buf []byte) (err error) { 280 done := 0 281 bl.Major_Version, done = binary.Uvarint(buf) 282 if done <= 0 { 283 return fmt.Errorf("Invalid Major Version in Block\n") 284 } 285 buf = buf[done:] 286 287 bl.Minor_Version, done = binary.Uvarint(buf) 288 if done <= 0 { 289 return fmt.Errorf("Invalid Minor Version in Block\n") 290 } 291 buf = buf[done:] 292 293 bl.Timestamp, done = binary.Uvarint(buf) 294 if done <= 0 { 295 return fmt.Errorf("Invalid Timestamp in Block\n") 296 } 297 buf = buf[done:] 298 299 //copy(bl.Prev_Hash[:], buf[:32]) // hash is always 32 byte 300 //buf = buf[32:] 301 302 bl.Nonce = binary.LittleEndian.Uint32(buf) 303 304 buf = buf[4:] 305 306 copy(bl.ExtraNonce[:], buf[0:32]) 307 308 buf = buf[32:] 309 310 // parse miner tx 311 err = bl.Miner_TX.DeserializeHeader(buf) 312 if err != nil { 313 return err 314 } 315 316 return 317 } 318 319 //parse entire block completely 320 func (bl *Block) Deserialize(buf []byte) (err error) { 321 done := 0 322 323 defer func() { 324 if r := recover(); r != nil { 325 fmt.Printf("Panic while deserialising block, block hex_dump below to make a testcase/debug\n") 326 fmt.Printf("%s\n", hex.EncodeToString(buf)) 327 328 fmt.Printf("Recovered while parsing block, Stack trace below block_hash ") 329 fmt.Printf("Stack trace \n%s", debug.Stack()) 330 err = fmt.Errorf("Invalid Block") 331 return 332 } 333 }() 334 335 err = bl.DeserializeHeader(buf) 336 if err != nil { 337 return fmt.Errorf("Block Header could not be parsed\n") 338 } 339 340 buf = buf[len(bl.SerializeHeader()):] // skup number of bytes processed 341 342 // read 32 byte proof 343 copy(bl.Proof[:], buf[0:32]) 344 buf = buf[32:] 345 346 // header finished here 347 348 // read and parse transaction 349 /*err = bl.Miner_tx.DeserializeHeader(buf) 350 351 if err != nil { 352 return fmt.Errorf("Cannot parse miner TX %x", buf) 353 } 354 355 // if tx was parse, make sure it's coin base 356 if len(bl.Miner_tx.Vin) != 1 || bl.Miner_tx.Vin[0].(transaction.Txin_gen).Height > config.MAX_CHAIN_HEIGHT { 357 // serialize transaction again to get the tx size, so as parsing could continue 358 return fmt.Errorf("Invalid Miner TX") 359 } 360 361 miner_tx_serialized_size := bl.Miner_tx.Serialize() 362 buf = buf[len(miner_tx_serialized_size):] 363 */ 364 365 tips_count, done := binary.Uvarint(buf) 366 if done <= 0 || done > 1 { 367 return fmt.Errorf("Invalid Tips count in Block\n") 368 } 369 buf = buf[done:] 370 371 // remember first tx is merkle root 372 373 for i := uint64(0); i < tips_count; i++ { 374 //fmt.Printf("Parsing transaction hash %d tx_count %d\n", i, tx_count) 375 var h crypto.Hash 376 copy(h[:], buf[:32]) 377 buf = buf[32:] 378 379 bl.Tips = append(bl.Tips, h) 380 381 } 382 383 //fmt.Printf("miner tx %x\n", miner_tx_serialized_size) 384 // read number of transactions 385 tx_count, done := binary.Uvarint(buf) 386 if done <= 0 { 387 return fmt.Errorf("Invalid Tx count in Block\n") 388 } 389 buf = buf[done:] 390 391 // remember first tx is merkle root 392 393 for i := uint64(0); i < tx_count; i++ { 394 //fmt.Printf("Parsing transaction hash %d tx_count %d\n", i, tx_count) 395 var h crypto.Hash 396 copy(h[:], buf[:32]) 397 buf = buf[32:] 398 399 bl.Tx_hashes = append(bl.Tx_hashes, h) 400 401 } 402 403 //fmt.Printf("%d member in tx hashes \n",len(bl.Tx_hashes)) 404 405 return 406 407 }