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.

215 lines
7.7 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. // refer https://cryptonote.org/cns/cns005.txt to understand slightly more ( it DOES NOT cover everything)
  23. // much of these constants are understood from tx_extra.h and cryptonote_format_utils.cpp
  24. // TODO pending test case
  25. type EXTRA_TAG byte
  26. const TX_EXTRA_PADDING EXTRA_TAG = 0 // followed by 1 byte of size, and then upto 255 bytes of padding
  27. const TX_PUBLIC_KEY EXTRA_TAG = 1 // follwed by 32 bytes of tx public key
  28. const TX_EXTRA_NONCE EXTRA_TAG = 2 // followed by 1 byte of size, and then upto 255 bytes of empty nonce
  29. // TX_EXTRA_MERGE_MINING_TAG we do NOT suppport merged mining at all
  30. // TX_EXTRA_MYSTERIOUS_MINERGATE_TAG as the name says mysterious we will not bring it
  31. // these 2 fields have complicated parsing of extra, other the code was really simple
  32. const TX_EXTRA_NONCE_PAYMENT_ID EXTRA_TAG = 0 // extra nonce within a non coinbase tx, can be unencrypted, is 32 bytes in size
  33. const TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID EXTRA_TAG = 1 // this is encrypted and is 9 bytes in size
  34. // the field is just named extra and contains CRITICAL information, though some is optional
  35. // parse extra data such as
  36. // tx public key must
  37. // payment id optional
  38. // encrypted payment id optional
  39. func (tx *Transaction) Parse_Extra() bool {
  40. var err error
  41. // var length uint64
  42. var length_int int
  43. buf := bytes.NewReader(tx.Extra)
  44. tx.Extra_map = map[EXTRA_TAG]interface{}{}
  45. tx.PaymentID_map = map[EXTRA_TAG]interface{}{}
  46. b := make([]byte, 1)
  47. //var r uint64
  48. var n int
  49. for i := 0; ; i++ {
  50. if buf.Len() == 0 {
  51. return true
  52. }
  53. n, err = buf.Read(b)
  54. if err != nil {
  55. return false
  56. }
  57. switch EXTRA_TAG(b[0]) {
  58. case TX_EXTRA_PADDING: // this is followed by 1 byte length, then length bytes of padding
  59. n, err = buf.Read(b)
  60. if err != nil {
  61. rlog.Tracef(1, "Extra padding length could not be parsed txhash %s", tx.GetHash())
  62. return false
  63. }
  64. length_int = int(b[0])
  65. padding := make([]byte, length_int, length_int)
  66. n, err = buf.Read(padding)
  67. if err != nil || n != int(length_int) {
  68. rlog.Tracef(1, "Extra padding could not be read txhash %s", tx.GetHash())
  69. return false
  70. }
  71. // Padding is not added to the extra map
  72. case TX_PUBLIC_KEY: // next 32 bytes are tx public key
  73. var pkey crypto.Key
  74. n, err = buf.Read(pkey[:])
  75. if err != nil || n != 32 {
  76. rlog.Tracef(1, "Tx public key could not be parsed len=%d err=%s txhash %s", n, err, tx.GetHash())
  77. return false
  78. }
  79. tx.Extra_map[TX_PUBLIC_KEY] = pkey
  80. case TX_EXTRA_NONCE: // this is followed by 1 byte length, then length bytes of data
  81. n, err = buf.Read(b)
  82. if err != nil {
  83. rlog.Tracef(1, "Extra nonce length could not be parsed txhash %s", tx.GetHash())
  84. return false
  85. }
  86. length_int = int(b[0])
  87. extra_nonce := make([]byte, length_int, length_int)
  88. n, err = buf.Read(extra_nonce)
  89. if err != nil || n != int(length_int) {
  90. rlog.Tracef(1, "Extra Nonce could not be read txhash %s", tx.GetHash())
  91. return false
  92. }
  93. switch length_int {
  94. case 33: // unencrypted 32 byte payment id
  95. if extra_nonce[0] == byte(TX_EXTRA_NONCE_PAYMENT_ID) {
  96. tx.PaymentID_map[TX_EXTRA_NONCE_PAYMENT_ID] = extra_nonce[1:]
  97. } else {
  98. rlog.Tracef(1, "Extra Nonce contains invalid payment id txhash %s", tx.GetHash())
  99. }
  100. case 9: // encrypted 9 byte payment id
  101. if extra_nonce[0] == byte(TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID) {
  102. tx.PaymentID_map[TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID] = extra_nonce[1:]
  103. } else {
  104. rlog.Tracef(1, "Extra Nonce contains invalid encrypted payment id txhash %s", tx.GetHash())
  105. }
  106. default: // consider it as general nonce
  107. // ignore anything else
  108. }
  109. tx.Extra_map[TX_EXTRA_NONCE] = extra_nonce
  110. // NO MORE TAGS are present
  111. default: // ignore any other unknown tag or data
  112. rlog.Tracef(1, "Unhandled TAG %d in tx %s\n", b[0], tx.GetHash())
  113. return true
  114. }
  115. }
  116. // we should not reach here
  117. //return true
  118. }
  119. // serialize an extra, this is only required while creating new transactions ( both miner and normal)
  120. // doing this on existing transaction will cause them to fail ( due to different placement order )
  121. func (tx *Transaction) Serialize_Extra() []byte {
  122. buf := bytes.NewBuffer(nil)
  123. // this is mandatory
  124. if _, ok := tx.Extra_map[TX_PUBLIC_KEY]; ok {
  125. buf.WriteByte(byte(TX_PUBLIC_KEY)) // write marker
  126. key := tx.Extra_map[TX_PUBLIC_KEY].(crypto.Key)
  127. buf.Write(key[:]) // write the key
  128. } else {
  129. rlog.Tracef(1, "TX does not contain a Public Key, not possible, the transaction will be rejected")
  130. }
  131. // if payment id are set, they replace nonce
  132. // first place unencrypted payment id
  133. if _, ok := tx.PaymentID_map[TX_EXTRA_NONCE_PAYMENT_ID]; ok {
  134. data_bytes := tx.PaymentID_map[TX_EXTRA_NONCE_PAYMENT_ID].([]byte)
  135. if len(data_bytes) == 32 { // payment id is valid
  136. header := append([]byte{byte(TX_EXTRA_NONCE_PAYMENT_ID)}, data_bytes...)
  137. tx.Extra_map[TX_EXTRA_NONCE] = header // overwrite extra nonce with this
  138. }
  139. rlog.Tracef(1, "unencrypted payment id size mismatch expected = %d actual %d", 32, len(data_bytes))
  140. }
  141. if _, ok := tx.PaymentID_map[TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID]; ok {
  142. data_bytes := tx.PaymentID_map[TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID].([]byte)
  143. if len(data_bytes) == 8 { // payment id is valid
  144. header := append([]byte{byte(TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID)}, data_bytes...)
  145. tx.Extra_map[TX_EXTRA_NONCE] = header // overwrite extra nonce with this
  146. }
  147. rlog.Tracef(1, "unencrypted payment id size mismatch expected = %d actual %d", 8, len(data_bytes))
  148. }
  149. // TX_EXTRA_NONCE is optional
  150. // if payment is present, it is packed as extra nonce
  151. if _, ok := tx.Extra_map[TX_EXTRA_NONCE]; ok {
  152. buf.WriteByte(byte(TX_EXTRA_NONCE)) // write marker
  153. data_bytes := tx.Extra_map[TX_EXTRA_NONCE].([]byte)
  154. if len(data_bytes) > 255 {
  155. rlog.Tracef(1, "TX extra none is spilling, trimming the nonce to 255 bytes")
  156. data_bytes = data_bytes[:]
  157. }
  158. buf.WriteByte(byte(len(data_bytes))) // write length of extra nonce single byte
  159. buf.Write(data_bytes[:]) // write the nonce data
  160. }
  161. // NOTE: we do not support adding padding for the sake of it
  162. return buf.Bytes()
  163. }
  164. // resize the nonce by this much bytes,
  165. // positive means add byte
  166. // negative means decrease size
  167. // this is only required during miner tx to solve chicken and problem
  168. /*
  169. func (tx *Transaction) Resize_Extra_Nonce(int resize_amount) {
  170. nonce_bytes := tx.Extra_map[TX_EXTRA_NONCE].([]byte)
  171. nonce_bytes = make([]byte, len(nonce_bytes)+resize_amount, len(nonce_bytes)+resize_amount)
  172. tx.Extra_map[TX_EXTRA_NONCE] = nonce_bytes
  173. tx.Extra = tx.Serialize_Extra()
  174. }
  175. */