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.

661 lines
16 KiB

  1. package blockchain
  2. import "fmt"
  3. import "bytes"
  4. import "encoding/binary"
  5. import "github.com/romana/rlog"
  6. import "github.com/deroproject/derosuite/crypto"
  7. import "github.com/deroproject/derosuite/crypto/ringct"
  8. const TXIN_GEN = byte(0xff)
  9. const TXIN_TO_SCRIPT = byte(0)
  10. const TXIN_TO_SCRIPTHASH = byte(1)
  11. const TXIN_TO_KEY = byte(2)
  12. const TXOUT_TO_SCRIPT = byte(0)
  13. const TXOUT_TO_SCRIPTHASH = byte(1)
  14. const TXOUT_TO_KEY = byte(2)
  15. var TX_IN_NAME = map[byte]string{
  16. TXIN_GEN: "Coinbase",
  17. TXIN_TO_SCRIPT: "To Script",
  18. TXIN_TO_SCRIPTHASH: "To Script hash",
  19. TXIN_TO_KEY: "To key",
  20. }
  21. const TRANSACTION = byte(0xcc)
  22. const BLOCK = byte(0xbb)
  23. /*
  24. VARIANT_TAG(binary_archive, cryptonote::txin_to_script, 0x0);
  25. VARIANT_TAG(binary_archive, cryptonote::txin_to_scripthash, 0x1);
  26. VARIANT_TAG(binary_archive, cryptonote::txin_to_key, 0x2);
  27. VARIANT_TAG(binary_archive, cryptonote::txout_to_script, 0x0);
  28. VARIANT_TAG(binary_archive, cryptonote::txout_to_scripthash, 0x1);
  29. VARIANT_TAG(binary_archive, cryptonote::txout_to_key, 0x2);
  30. VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc);
  31. VARIANT_TAG(binary_archive, cryptonote::block, 0xbb);
  32. */
  33. /* outputs */
  34. type Txout_to_script struct {
  35. // std::vector<crypto::public_key> keys;
  36. // std::vector<uint8_t> script;
  37. Keys [][32]byte
  38. Script []byte
  39. /* BEGIN_SERIALIZE_OBJECT()
  40. FIELD(keys)
  41. FIELD(script)
  42. END_SERIALIZE()
  43. */
  44. }
  45. type Txout_to_scripthash struct {
  46. //crypto::hash hash;
  47. Hash [32]byte
  48. }
  49. type Txout_to_key struct {
  50. Key crypto.Key
  51. // Mask [32]byte `json:"-"`
  52. /*txout_to_key() { }
  53. txout_to_key(const crypto::public_key &_key) : key(_key) { }
  54. crypto::public_key key;*/
  55. }
  56. // there can be only 4 types if inputs
  57. // used by miner
  58. type Txin_gen struct {
  59. Height uint64 // stored as varint
  60. }
  61. type Txin_to_script struct {
  62. Prev [32]byte
  63. Prevout uint64
  64. Sigset []byte
  65. /* BEGIN_SERIALIZE_OBJECT()
  66. FIELD(prev)
  67. VARINT_FIELD(prevout)
  68. FIELD(sigset)
  69. END_SERIALIZE()
  70. */
  71. }
  72. type Txin_to_scripthash struct {
  73. Prev [32]byte
  74. Prevout uint64
  75. Script Txout_to_script
  76. Sigset []byte
  77. /* BEGIN_SERIALIZE_OBJECT()
  78. FIELD(prev)
  79. VARINT_FIELD(prevout)
  80. FIELD(script)
  81. FIELD(sigset)
  82. END_SERIALIZE()
  83. */
  84. }
  85. type Txin_to_key struct {
  86. Amount uint64
  87. Key_offsets []uint64 // this is encoded as a varint for length and then all offsets are stored as varint
  88. //crypto::key_image k_image; // double spending protection
  89. K_image crypto.Hash `json:"k_image"` // key image
  90. /* BEGIN_SERIALIZE_OBJECT()
  91. VARINT_FIELD(amount)
  92. FIELD(key_offsets)
  93. FIELD(k_image)
  94. END_SERIALIZE()
  95. */
  96. }
  97. type Txin_v interface{} // it can only be txin_gen, txin_to_script, txin_to_scripthash, txin_to_key
  98. type Tx_out struct {
  99. Amount uint64
  100. Target interface{} // txout_target_v ;, it can only be txout_to_script, txout_to_scripthash, txout_to_key
  101. /* BEGIN_SERIALIZE_OBJECT()
  102. VARINT_FIELD(amount)
  103. FIELD(target)
  104. END_SERIALIZE()
  105. */
  106. }
  107. // the core transaction
  108. type Transaction_Prefix struct {
  109. Version uint64 `json:"version"`
  110. Unlock_Time uint64 `json:"unlock_time"`
  111. Vin []Txin_v
  112. Vout []Tx_out
  113. Extra []byte
  114. ExtraType byte `json:"-"`
  115. }
  116. type Transaction struct {
  117. Transaction_Prefix
  118. // same as Transaction_Prefix
  119. // Signature not sure of what form
  120. Signature []Signature_v1 `json:"-"` // old format, the array size is always equal to vin length,
  121. //Signature_RCT RCT_Signature // version 2
  122. RctSignature *ringct.RctSig
  123. Expanded bool `json:"-"`
  124. }
  125. func (tx *Transaction) GetHash() (result crypto.Hash) {
  126. switch tx.Version {
  127. case 1:
  128. result = crypto.Hash(crypto.Keccak256(tx.SerializeHeader()))
  129. case 2:
  130. // version 2 requires first computing 3 separate hashes
  131. // prefix, rctBase and rctPrunable
  132. // and then hashing the hashes together to get the final hash
  133. prefixHash := tx.GetPrefixHash()
  134. rctBaseHash := tx.RctSignature.BaseHash()
  135. rctPrunableHash := tx.RctSignature.PrunableHash()
  136. result = crypto.Hash(crypto.Keccak256(prefixHash[:], rctBaseHash[:], rctPrunableHash[:]))
  137. default:
  138. panic("Transaction version cannot be zero")
  139. return
  140. }
  141. return
  142. }
  143. func (tx *Transaction) GetPrefixHash() (result crypto.Hash) {
  144. result = crypto.Keccak256(tx.SerializeHeader())
  145. return result
  146. }
  147. func (tx *Transaction) DeserializeHeader(buf []byte) (err error) {
  148. Key_offset_count := uint64(0) // used to calculate expected signatures in v1
  149. Mixin := -1
  150. tx.Clear() // clear existing
  151. //Mixin_count := 0 // for signature purpose
  152. done := 0
  153. tx.Version, done = binary.Uvarint(buf)
  154. if done <= 0 {
  155. return fmt.Errorf("Invalid Version in Transaction\n")
  156. }
  157. rlog.Tracef(10, "transaction version %d\n", tx.Version)
  158. buf = buf[done:]
  159. tx.Unlock_Time, done = binary.Uvarint(buf)
  160. if done <= 0 {
  161. return fmt.Errorf("Invalid Unlock_Time in Transaction\n")
  162. }
  163. buf = buf[done:]
  164. // parse vin length
  165. vin_length, done := binary.Uvarint(buf)
  166. if done <= 0 {
  167. return fmt.Errorf("Invalid Vin length in Transaction\n")
  168. }
  169. buf = buf[done:]
  170. if vin_length == 0 {
  171. return fmt.Errorf("Vin input cannot be zero in Transaction\n")
  172. }
  173. coinbase_done := false
  174. rlog.Tracef(10, "vin length %d\n", vin_length)
  175. for i := uint64(0); i < vin_length; i++ {
  176. vin_type := buf[0]
  177. buf = buf[1:] // consume 1 more byte
  178. rlog.Tracef(10, "Processing i %d vin_type %s hex %x\n", i, TX_IN_NAME[vin_type], buf[:40])
  179. switch vin_type {
  180. case TXIN_GEN:
  181. rlog.Tracef(10, "Coinbase transaction\n")
  182. if coinbase_done {
  183. return fmt.Errorf("Transaction cannot have multiple coin base transaction\n")
  184. }
  185. var current_vin Txin_gen
  186. current_vin.Height, done = binary.Uvarint(buf)
  187. if done <= 0 {
  188. return fmt.Errorf("Invalid Height for Txin_gen vin in Transaction\n")
  189. }
  190. buf = buf[done:]
  191. tx.Vin = append(tx.Vin, current_vin)
  192. coinbase_done = true // we can no longer have coin base
  193. case TXIN_TO_SCRIPT:
  194. panic("TXIN_TO_SCRIPT not implemented")
  195. case TXIN_TO_SCRIPTHASH:
  196. panic("TXIN_TO_SCRIPTHASH not implemented")
  197. case TXIN_TO_KEY:
  198. var current_vin Txin_to_key
  199. // parse Amount
  200. current_vin.Amount, done = binary.Uvarint(buf)
  201. if done <= 0 {
  202. return fmt.Errorf("Invalid Amount for Txin_to_key vin in Transaction\n")
  203. }
  204. buf = buf[done:]
  205. //fmt.Printf("Remaining data %x\n", buf[:20]);
  206. mixin_count, done := binary.Uvarint(buf)
  207. if done <= 0 {
  208. return fmt.Errorf("Invalid offset_count for Txin_to_key vin in Transaction\n")
  209. }
  210. buf = buf[done:]
  211. // safety check mixin cannot be larger than say x
  212. if mixin_count > 40 {
  213. return fmt.Errorf("Mixin cannot be larger than 40\n")
  214. }
  215. if Mixin < 0 {
  216. Mixin = int(mixin_count)
  217. }
  218. if Mixin != int(mixin_count) { // all vins must have same mixin
  219. return fmt.Errorf("Different mixin in Transaction\n")
  220. }
  221. //Mixin_input_count += Mixin
  222. for j := uint64(0); j < mixin_count; j++ {
  223. offset, done := binary.Uvarint(buf)
  224. if done <= 0 {
  225. return fmt.Errorf("Invalid key offset for Txin_to_key vin in Transaction\n")
  226. }
  227. buf = buf[done:]
  228. current_vin.Key_offsets = append(current_vin.Key_offsets, offset)
  229. }
  230. Key_offset_count += mixin_count
  231. copy(current_vin.K_image[:], buf[:32]) // copy key image
  232. buf = buf[32:] // consume key image bytes
  233. tx.Vin = append(tx.Vin, current_vin)
  234. // panic("TXIN_TO_KEY not implemented")
  235. default:
  236. panic("Invalid VIN type in Transaction")
  237. fmt.Errorf("Invalid VIN type in Transaction\n")
  238. }
  239. }
  240. //fmt.Printf("TX before vout %+v\n", tx)
  241. //fmt.Printf("buf before vout length %x\n", buf)
  242. vout_length, done := binary.Uvarint(buf)
  243. if done <= 0 {
  244. return fmt.Errorf("Invalid Vout length in Transaction\n")
  245. }
  246. buf = buf[done:]
  247. if vout_length == 0 {
  248. return fmt.Errorf("Vout cannot be zero in Transaction\n")
  249. }
  250. for i := uint64(0); i < vout_length; i++ {
  251. // amount is decoded earlier
  252. amount, done := binary.Uvarint(buf)
  253. if done <= 0 {
  254. return fmt.Errorf("Invalid Amount in Transaction\n")
  255. }
  256. buf = buf[done:]
  257. // decode vout type
  258. vout_type := buf[0]
  259. buf = buf[1:] // consume 1 more byte
  260. rlog.Tracef(10, "Vout Amount length %d vout type %d \n", amount, vout_type)
  261. if tx.Version == 1 && amount == 0 { // version 2 can have any amount
  262. return fmt.Errorf("Amount cannot be zero in Transaction\n")
  263. }
  264. switch vout_type {
  265. case TXOUT_TO_SCRIPT:
  266. //fmt.Printf("out to script\n")
  267. panic("TXOUT_TO_SCRIPT not implemented")
  268. case TXOUT_TO_SCRIPTHASH:
  269. //fmt.Printf("out to scripthash\n")
  270. var current_vout Txout_to_scripthash
  271. copy(current_vout.Hash[:], buf[0:32])
  272. tx.Vout = append(tx.Vout, Tx_out{Amount: amount, Target: current_vout})
  273. buf = buf[32:]
  274. //panic("TXOUT_TO_SCRIPTHASH not implemented")
  275. case TXOUT_TO_KEY:
  276. //fmt.Printf("out to key\n")
  277. var current_vout Txout_to_key
  278. copy(current_vout.Key[:], buf[0:32])
  279. buf = buf[32:]
  280. //Mixin_input_count++
  281. tx.Vout = append(tx.Vout, Tx_out{Amount: amount, Target: current_vout})
  282. default:
  283. fmt.Errorf("Invalid VOUT type in Transaction\n")
  284. }
  285. }
  286. // fmt.Printf("Extra %x\n", buf)
  287. // decode extra
  288. extra_length, done := binary.Uvarint(buf)
  289. if done <= 0 {
  290. return fmt.Errorf("Invalid Extra length in Transaction\n")
  291. }
  292. buf = buf[done:]
  293. // BUG extra needs to be processed in a loop till we load all extra fields
  294. //tx.ExtraType = buf[0]
  295. // buf = buf[1:] // consume 1 more byte
  296. // extra_length--
  297. rlog.Tracef(8, "extra len %d have %d \n", extra_length, len(buf))
  298. tx.Extra = buf[:extra_length]
  299. // whatever is leftover is signature
  300. buf = buf[extra_length:] // consume more bytes
  301. switch tx.Version {
  302. case 1: // old style signatures, load value
  303. for i := uint64(0); i < Key_offset_count; i++ {
  304. var s Signature_v1
  305. copy(s.R[:], buf[:32])
  306. copy(s.C[:], buf[32:64])
  307. tx.Signature = append(tx.Signature, s)
  308. buf = buf[SIGNATURE_V1_LENGTH:]
  309. }
  310. case 2:
  311. bufreader := bytes.NewReader(buf)
  312. Mixin -= 1 // one is ours, rest are mixin
  313. tx.RctSignature, err = ringct.ParseRingCtSignature(bufreader, len(tx.Vin), len(tx.Vout), Mixin)
  314. if err != nil {
  315. return err
  316. }
  317. }
  318. /* we must deserialize signature some where else
  319. //fmt.Printf("extra bytes %x\n",buf)
  320. //fmt.Printf("signature len %d should be %d\n",len(buf),len(tx.Vin)*SIGNATURE_V1_LENGTH)
  321. fmt.Printf("signature len %d should be %d\n",len(buf),Key_offset_count*SIGNATURE_V1_LENGTH)
  322. switch tx.Version {
  323. case 1 : // old style signatures, load value
  324. for i := uint64(0); i < Key_offset_count;i++{
  325. var s Signature_v1
  326. copy(s.R[:],buf[:32])
  327. copy(s.C[:],buf[32:64])
  328. tx.Signature = append(tx.Signature, s)
  329. buf = buf[SIGNATURE_V1_LENGTH:]
  330. }
  331. case 2:
  332. tx.Signature_RCT.Type, done = binary.Uvarint(buf)
  333. if done <= 0 {
  334. return fmt.Errorf("Invalid RCT signature in Transaction\n")
  335. }
  336. buf = buf[done:]
  337. switch tx.Signature_RCT.Type {
  338. case 0 : // no signature break
  339. case 1 :
  340. tx.Signature_RCT.TxnFee, done = binary.Uvarint(buf)
  341. if done <= 0 {
  342. return fmt.Errorf("Invalid txn fee in Transaction\n")
  343. }
  344. buf = buf[done:]
  345. fmt.Printf("RCT signature type %d Fee %d\n",tx.Signature_RCT.Type, tx.Signature_RCT.TxnFee)
  346. // how many masked inputs depends on number of masked outouts
  347. for i := (0); i < len(tx.Vout);i++{
  348. // read masked input
  349. var info ECDHinfo
  350. copy(info.Mask[:], buf[0:32])
  351. copy(info.Amount[:], buf[32:64])
  352. tx.Signature_RCT.Amounts = append(tx.Signature_RCT.Amounts, info)
  353. buf = buf[64:]
  354. }
  355. // now parse the public keys
  356. for i := (0); i < len(tx.Vout);i++{
  357. // read masked input
  358. var tmp [32]byte
  359. copy(tmp[:], buf[0:32])
  360. tx.Signature_RCT.OutPK = append(tx.Signature_RCT.OutPK, tmp)
  361. buf = buf[32:]
  362. }
  363. case 2 : // panic("ringct type 2 currently not handled")
  364. default:
  365. panic("unknown signature style")
  366. }
  367. default:
  368. panic("unknown transaction version \n")
  369. }
  370. */
  371. rlog.Tracef(8, "TX deserialized %+v\n", tx)
  372. /*
  373. data.Local_time = binary.LittleEndian.Uint64( buf[24:], )
  374. data.Local_Port = binary.LittleEndian.Uint32( buf[41:])
  375. _ = data.Network_UUID.UnmarshalBinary(buf[58:58+16])
  376. data.Peer_ID = binary.LittleEndian.Uint64( buf[83:] )
  377. */
  378. return nil //fmt.Errorf("Done Transaction\n")
  379. }
  380. // calculated prefi has signature
  381. func (tx *Transaction) PrefixHash() {
  382. }
  383. // calculated prefi has signature
  384. func (tx *Transaction) Clear() {
  385. // clean the transaction everything
  386. tx.Version = 0
  387. tx.Unlock_Time = 0
  388. tx.Vin = tx.Vin[:0]
  389. tx.Vout = tx.Vout[:0]
  390. tx.Extra = tx.Extra[:0]
  391. }
  392. func (tx *Transaction) SerializeHeader() []byte {
  393. var serialised_header bytes.Buffer
  394. buf := make([]byte, binary.MaxVarintLen64)
  395. n := binary.PutUvarint(buf, tx.Version)
  396. serialised_header.Write(buf[:n])
  397. n = binary.PutUvarint(buf, tx.Unlock_Time)
  398. serialised_header.Write(buf[:n])
  399. /*if len(tx.Vin) < 1 {
  400. panic("No vins")
  401. }*/
  402. n = binary.PutUvarint(buf, uint64(len(tx.Vin)))
  403. serialised_header.Write(buf[:n])
  404. for _, current_vin := range tx.Vin {
  405. switch current_vin.(type) {
  406. case Txin_gen:
  407. serialised_header.WriteByte(TXIN_GEN)
  408. n = binary.PutUvarint(buf, current_vin.(Txin_gen).Height)
  409. serialised_header.Write(buf[:n])
  410. case Txin_to_key:
  411. serialised_header.WriteByte(TXIN_TO_KEY)
  412. n = binary.PutUvarint(buf, current_vin.(Txin_to_key).Amount)
  413. serialised_header.Write(buf[:n])
  414. // number of Ring member
  415. n = binary.PutUvarint(buf, uint64(len(current_vin.(Txin_to_key).Key_offsets)))
  416. serialised_header.Write(buf[:n])
  417. // write ring members
  418. for _, offset := range current_vin.(Txin_to_key).Key_offsets {
  419. n = binary.PutUvarint(buf, offset)
  420. serialised_header.Write(buf[:n])
  421. }
  422. // dump key image, interface needs a concrete type feor accessing array
  423. cvin := current_vin.(Txin_to_key)
  424. serialised_header.Write(cvin.K_image[:])
  425. }
  426. }
  427. // time to serialize vouts
  428. if len(tx.Vout) < 1 {
  429. panic("No vout")
  430. }
  431. n = binary.PutUvarint(buf, uint64(len(tx.Vout)))
  432. serialised_header.Write(buf[:n])
  433. for _, current_vout := range tx.Vout {
  434. // dump amount
  435. n := binary.PutUvarint(buf, current_vout.Amount)
  436. serialised_header.Write(buf[:n])
  437. switch current_vout.Target.(type) {
  438. case Txout_to_key:
  439. serialised_header.WriteByte(TXOUT_TO_KEY)
  440. target := current_vout.Target.(Txout_to_key)
  441. serialised_header.Write(target.Key[:])
  442. //serialised_header.Write(current_vout.Target.(Txout_to_key).Key[:])
  443. default:
  444. panic("This type of Txout not suppported")
  445. }
  446. }
  447. // dump any extras
  448. n = binary.PutUvarint(buf, uint64(len(tx.Extra)))
  449. serialised_header.Write(buf[:n])
  450. //rlog.Tracef("Extra length %d while serializing\n ", len(tx.Extra))
  451. serialised_header.Write(tx.Extra[:])
  452. return serialised_header.Bytes()
  453. }
  454. // serialize entire transaction include signature
  455. func (tx *Transaction) Serialize() []byte {
  456. header_bytes := tx.SerializeHeader()
  457. base_bytes := tx.RctSignature.SerializeBase()
  458. prunable := tx.RctSignature.SerializePrunable()
  459. buf := append(header_bytes, base_bytes...)
  460. buf = append(buf, prunable...)
  461. return buf
  462. }
  463. /*
  464. func (tx *Transaction) IsCoinbase() (result bool){
  465. // check whether the type is Txin.get
  466. if len(tx.Vin) != 0 { // coinbase transactions have no vin
  467. return
  468. }
  469. if tx.Vout[0].(Target) != 0 { // coinbase transactions have no vin
  470. return
  471. }
  472. }*/