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.

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