github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/transaction/transaction.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 transaction
    18  
    19  import "fmt"
    20  import "bytes"
    21  import "encoding/binary"
    22  
    23  import "github.com/romana/rlog"
    24  
    25  import "github.com/deroproject/derosuite/crypto"
    26  import "github.com/deroproject/derosuite/crypto/ringct"
    27  
    28  const TXIN_GEN = byte(0xff)
    29  const TXIN_TO_SCRIPT = byte(0)
    30  const TXIN_TO_SCRIPTHASH = byte(1)
    31  const TXIN_TO_KEY = byte(2)
    32  
    33  const TXOUT_TO_SCRIPT = byte(0)
    34  const TXOUT_TO_SCRIPTHASH = byte(1)
    35  const TXOUT_TO_KEY = byte(2)
    36  
    37  var TX_IN_NAME = map[byte]string{
    38  	TXIN_GEN:           "Coinbase",
    39  	TXIN_TO_SCRIPT:     "To Script",
    40  	TXIN_TO_SCRIPTHASH: "To Script hash",
    41  	TXIN_TO_KEY:        "To key",
    42  }
    43  
    44  const TRANSACTION = byte(0xcc)
    45  const BLOCK = byte(0xbb)
    46  
    47  /*
    48  VARIANT_TAG(binary_archive, cryptonote::txin_to_script, 0x0);
    49  VARIANT_TAG(binary_archive, cryptonote::txin_to_scripthash, 0x1);
    50  VARIANT_TAG(binary_archive, cryptonote::txin_to_key, 0x2);
    51  VARIANT_TAG(binary_archive, cryptonote::txout_to_script, 0x0);
    52  VARIANT_TAG(binary_archive, cryptonote::txout_to_scripthash, 0x1);
    53  VARIANT_TAG(binary_archive, cryptonote::txout_to_key, 0x2);
    54  VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc);
    55  VARIANT_TAG(binary_archive, cryptonote::block, 0xbb);
    56  */
    57  /* outputs */
    58  
    59  type Txout_to_script struct {
    60  	// std::vector<crypto::public_key> keys;
    61  	//  std::vector<uint8_t> script;
    62  
    63  	Keys   [][32]byte
    64  	Script []byte
    65  
    66  	/*  BEGIN_SERIALIZE_OBJECT()
    67  	      FIELD(keys)
    68  	      FIELD(script)
    69  	    END_SERIALIZE()
    70  
    71  	*/
    72  }
    73  
    74  type Txout_to_scripthash struct {
    75  	//crypto::hash hash;
    76  	Hash [32]byte
    77  }
    78  
    79  type Txout_to_key struct {
    80  	Key crypto.Key
    81  	//	Mask [32]byte `json:"-"`
    82  	/*txout_to_key() { }
    83  	  txout_to_key(const crypto::public_key &_key) : key(_key) { }
    84  	  crypto::public_key key;*/
    85  
    86  }
    87  
    88  // there can be only 4 types if inputs
    89  
    90  // used by miner
    91  type Txin_gen struct {
    92  	Height uint64 // stored as varint
    93  }
    94  
    95  type Txin_to_script struct {
    96  	Prev    [32]byte
    97  	Prevout uint64
    98  	Sigset  []byte
    99  
   100  	/* BEGIN_SERIALIZE_OBJECT()
   101  	     FIELD(prev)
   102  	     VARINT_FIELD(prevout)
   103  	     FIELD(sigset)
   104  	   END_SERIALIZE()
   105  	*/
   106  }
   107  
   108  type Txin_to_scripthash struct {
   109  	Prev    [32]byte
   110  	Prevout uint64
   111  	Script  Txout_to_script
   112  	Sigset  []byte
   113  
   114  	/* BEGIN_SERIALIZE_OBJECT()
   115  	     FIELD(prev)
   116  	     VARINT_FIELD(prevout)
   117  	     FIELD(script)
   118  	     FIELD(sigset)
   119  	   END_SERIALIZE()
   120  	*/
   121  }
   122  
   123  type Txin_to_key struct {
   124  	Amount      uint64
   125  	Key_offsets []uint64 // this is encoded as a varint for length and then all offsets are stored as varint
   126  	//crypto::key_image k_image;      // double spending protection
   127  	K_image crypto.Hash `json:"k_image"` // key image
   128  
   129  	/* BEGIN_SERIALIZE_OBJECT()
   130  	     VARINT_FIELD(amount)
   131  	     FIELD(key_offsets)
   132  	     FIELD(k_image)
   133  	   END_SERIALIZE()
   134  	*/
   135  }
   136  
   137  type Txin_v interface{} // it can only be txin_gen, txin_to_script, txin_to_scripthash, txin_to_key
   138  
   139  type Tx_out struct {
   140  	Amount uint64
   141  	Target interface{} // txout_target_v ;, it can only be  txout_to_script, txout_to_scripthash, txout_to_key
   142  
   143  	/* BEGIN_SERIALIZE_OBJECT()
   144  	     VARINT_FIELD(amount)
   145  	     FIELD(target)
   146  	   END_SERIALIZE()
   147  	*/
   148  
   149  }
   150  
   151  // the core transaction
   152  type Transaction_Prefix struct {
   153  	Version       uint64 `json:"version"`
   154  	Unlock_Time   uint64 `json:"unlock_time"` // used to lock first output
   155  	Vin           []Txin_v
   156  	Vout          []Tx_out
   157  	Extra         []byte
   158  	Extra_map     map[EXTRA_TAG]interface{} `json:"-"` // all information parsed from extra is placed here
   159  	PaymentID_map map[EXTRA_TAG]interface{} `json:"-"` // payments id parsed or set are placed her
   160  	ExtraType     byte                      `json:"-"` // NOT used, candidate for deletion
   161  }
   162  
   163  type Transaction struct {
   164  	Transaction_Prefix
   165  	// same as Transaction_Prefix
   166  	// Signature  not sure of what form
   167  	Signature []Signature_v1 `json:"-"` // old format, the array size is always equal to vin length,
   168  	//Signature_RCT RCT_Signature  // version 2
   169  
   170  	RctSignature *ringct.RctSig
   171  	Expanded     bool `json:"-"`
   172  }
   173  
   174  func (tx *Transaction) GetHash() (result crypto.Hash) {
   175  	switch tx.Version {
   176  
   177  	/*case 1:
   178  	result = crypto.Hash(crypto.Keccak256(tx.SerializeHeader()))
   179  	*/
   180  
   181  	case 2:
   182  		// version 2 requires first computing 3 separate hashes
   183  		// prefix, rctBase and rctPrunable
   184  		// and then hashing the hashes together to get the final hash
   185  		prefixHash := tx.GetPrefixHash()
   186  		rctBaseHash := tx.RctSignature.BaseHash()
   187  		rctPrunableHash := tx.RctSignature.PrunableHash()
   188  		result = crypto.Hash(crypto.Keccak256(prefixHash[:], rctBaseHash[:], rctPrunableHash[:]))
   189  	default:
   190  		panic("Transaction version unknown")
   191  
   192  	}
   193  
   194  	return
   195  }
   196  
   197  func (tx *Transaction) GetPrefixHash() (result crypto.Hash) {
   198  	result = crypto.Keccak256(tx.SerializeHeader())
   199  	return result
   200  }
   201  
   202  // returns whether the tx is coinbase
   203  func (tx *Transaction) IsCoinbase() (result bool) {
   204  	switch tx.Vin[0].(type) {
   205  	case Txin_gen:
   206  		return true
   207  	default:
   208  		return false
   209  	}
   210  }
   211  
   212  func (tx *Transaction) DeserializeHeader(buf []byte) (err error) {
   213  
   214  	Key_offset_count := uint64(0) // used to calculate expected signatures in v1
   215  
   216  	Mixin := -1
   217  
   218  	tx.Clear() // clear existing
   219  
   220  	//Mixin_count := 0 // for signature purpose
   221  
   222  	done := 0
   223  	tx.Version, done = binary.Uvarint(buf)
   224  	if done <= 0 {
   225  		return fmt.Errorf("Invalid Version in Transaction\n")
   226  	}
   227  
   228  	if tx.Version != 2 {
   229  		return fmt.Errorf("Transaction version not equal to 2 \n")
   230  	}
   231  	rlog.Tracef(10, "transaction version %d\n", tx.Version)
   232  
   233  	buf = buf[done:]
   234  	tx.Unlock_Time, done = binary.Uvarint(buf)
   235  	if done <= 0 {
   236  		return fmt.Errorf("Invalid Unlock_Time in Transaction\n")
   237  	}
   238  	buf = buf[done:]
   239  
   240  	// parse vin length
   241  	vin_length, done := binary.Uvarint(buf)
   242  	if done <= 0 {
   243  		return fmt.Errorf("Invalid Vin length in Transaction\n")
   244  	}
   245  	buf = buf[done:]
   246  
   247  	if vin_length == 0 {
   248  		return fmt.Errorf("Vin input cannot be zero in Transaction\n")
   249  
   250  	}
   251  
   252  	rlog.Tracef(10, "vin length %d\n", vin_length)
   253  
   254  	for i := uint64(0); i < vin_length; i++ {
   255  
   256  		vin_type := buf[0]
   257  
   258  		buf = buf[1:] // consume 1 more byte
   259  
   260  		rlog.Tracef(10, "Processing i %d  vin_type %s  hex %x\n", i, TX_IN_NAME[vin_type], buf[:40])
   261  
   262  		switch vin_type {
   263  		case TXIN_GEN:
   264  			rlog.Tracef(10, "Coinbase transaction\n")
   265  
   266  			var current_vin Txin_gen
   267  			current_vin.Height, done = binary.Uvarint(buf)
   268  			if done <= 0 {
   269  				return fmt.Errorf("Invalid Height for Txin_gen vin in Transaction\n")
   270  			}
   271  			buf = buf[done:]
   272  			tx.Vin = append(tx.Vin, current_vin)
   273  
   274  		/*case TXIN_TO_SCRIPT:
   275  			panic("TXIN_TO_SCRIPT not implemented")
   276  		case TXIN_TO_SCRIPTHASH:
   277  			panic("TXIN_TO_SCRIPTHASH not implemented")
   278  		*/
   279  		case TXIN_TO_KEY:
   280  			var current_vin Txin_to_key
   281  
   282  			// parse Amount
   283  			current_vin.Amount, done = binary.Uvarint(buf)
   284  			if done <= 0 {
   285  				return fmt.Errorf("Invalid Amount for Txin_to_key vin in Transaction\n")
   286  			}
   287  			buf = buf[done:]
   288  
   289  			if current_vin.Amount != 0 {
   290  				return fmt.Errorf("V2 Transactions have all input amount as zero\n")
   291  			}
   292  
   293  			//fmt.Printf("Remaining data %x\n", buf[:20]);
   294  
   295  			mixin_count, done := binary.Uvarint(buf)
   296  			if done <= 0 {
   297  				return fmt.Errorf("Invalid offset_count for Txin_to_key vin in Transaction\n")
   298  			}
   299  			buf = buf[done:]
   300  
   301  			// safety check mixin cannot be larger than say x
   302  			// do we need a safety check
   303  			if mixin_count > 4000 {
   304  				return fmt.Errorf("Mixin cannot be larger than 400\n")
   305  			}
   306  
   307  			if Mixin < 0 {
   308  				Mixin = int(mixin_count)
   309  			}
   310  
   311  			if Mixin != int(mixin_count) { // all vins must have same mixin
   312  				return fmt.Errorf("Different mixin in Transaction\n")
   313  
   314  			}
   315  
   316  			//Mixin_input_count += Mixin
   317  
   318  			for j := uint64(0); j < mixin_count; j++ {
   319  				offset, done := binary.Uvarint(buf)
   320  				if done <= 0 {
   321  					return fmt.Errorf("Invalid key offset for Txin_to_key vin in Transaction\n")
   322  				}
   323  				buf = buf[done:]
   324  				current_vin.Key_offsets = append(current_vin.Key_offsets, offset)
   325  			}
   326  
   327  			Key_offset_count += mixin_count
   328  
   329  			copy(current_vin.K_image[:], buf[:32]) // copy key image
   330  
   331  			buf = buf[32:] // consume key image bytes
   332  
   333  			tx.Vin = append(tx.Vin, current_vin)
   334  
   335  			// panic("TXIN_TO_KEY not implemented")
   336  
   337  		default:
   338  			return fmt.Errorf("Invalid VIN type in Transaction")
   339  
   340  		}
   341  
   342  	}
   343  
   344  	//fmt.Printf("TX before vout %+v\n", tx)
   345  
   346  	//fmt.Printf("buf before vout length %x\n", buf)
   347  	vout_length, done := binary.Uvarint(buf)
   348  	if done <= 0 {
   349  		return fmt.Errorf("Invalid Vout length in Transaction\n")
   350  	}
   351  	buf = buf[done:]
   352  
   353  	if vout_length == 0 {
   354  		return fmt.Errorf("Vout cannot be zero in Transaction\n")
   355  	}
   356  
   357  	for i := uint64(0); i < vout_length; i++ {
   358  
   359  		// amount is decoded earlier
   360  
   361  		amount, done := binary.Uvarint(buf)
   362  		if done <= 0 {
   363  			return fmt.Errorf("Invalid Amount in Transaction\n")
   364  		}
   365  		buf = buf[done:]
   366  
   367  		/*if amount != 0 {
   368  		    return fmt.Errorf("V2 Transactions have all output amount as zero\n")
   369  		}*/
   370  
   371  		// decode vout type
   372  
   373  		vout_type := buf[0]
   374  		buf = buf[1:] // consume 1 more byte
   375  
   376  		rlog.Tracef(10, "Vout Amount length %d  vout type %d   \n", amount, vout_type)
   377  
   378  		/*if tx.Version == 2 && amount != 0 { // version 2 must have amount 0
   379  			return fmt.Errorf("Amount must be zero in Transaction\n")
   380  		}*/
   381  
   382  		switch vout_type {
   383  		/*case TXOUT_TO_SCRIPT:
   384  			//fmt.Printf("out to script\n")
   385  			panic("TXOUT_TO_SCRIPT not implemented")
   386  		case TXOUT_TO_SCRIPTHASH:
   387  			//fmt.Printf("out to scripthash\n")
   388  			var current_vout Txout_to_scripthash
   389  			copy(current_vout.Hash[:], buf[0:32])
   390  			tx.Vout = append(tx.Vout, Tx_out{Amount: amount, Target: current_vout})
   391  
   392  			buf = buf[32:]
   393  
   394  			//panic("TXOUT_TO_SCRIPTHASH not implemented")
   395  		*/
   396  		case TXOUT_TO_KEY:
   397  			//fmt.Printf("out to key\n")
   398  
   399  			var current_vout Txout_to_key
   400  
   401  			copy(current_vout.Key[:], buf[0:32])
   402  			buf = buf[32:]
   403  
   404  			//Mixin_input_count++
   405  
   406  			tx.Vout = append(tx.Vout, Tx_out{Amount: amount, Target: current_vout})
   407  
   408  		default:
   409  			return fmt.Errorf("Invalid VOUT type in Transaction\n")
   410  
   411  		}
   412  
   413  	}
   414  
   415  	// fmt.Printf("Extra %x\n", buf)
   416  	// decode extra
   417  	extra_length, done := binary.Uvarint(buf)
   418  	if done <= 0 {
   419  		return fmt.Errorf("Invalid Extra length in Transaction\n")
   420  	}
   421  	buf = buf[done:]
   422  
   423  	// BUG extra needs to be processed in a loop till we load all extra fields
   424  
   425  	//tx.ExtraType = buf[0]
   426  	//    buf = buf[1:] // consume 1 more byte
   427  
   428  	//    extra_length--
   429  
   430  	rlog.Tracef(8, "extra len %d  have %d \n", extra_length, len(buf))
   431  	tx.Extra = buf[:extra_length]
   432  
   433  	// whatever is leftover is signature
   434  	buf = buf[extra_length:] // consume more bytes
   435  
   436  	switch tx.Version {
   437  	/*case 1: // old style signatures, load value
   438  	for i := uint64(0); i < Key_offset_count; i++ {
   439  		var s Signature_v1
   440  		copy(s.R[:], buf[:32])
   441  		copy(s.C[:], buf[32:64])
   442  		tx.Signature = append(tx.Signature, s)
   443  		buf = buf[SIGNATURE_V1_LENGTH:]
   444  	}
   445  	*/
   446  
   447  	case 2:
   448  		bufreader := bytes.NewReader(buf)
   449  
   450  		Mixin -= 1 // one is ours, rest are mixin
   451  
   452  		tx.RctSignature, err = ringct.ParseRingCtSignature(bufreader, len(tx.Vin), len(tx.Vout), Mixin)
   453  		if err != nil {
   454  			return err
   455  		}
   456  
   457  		// we can expand and set some bulletproofs for later on verification,
   458  		/*
   459  					if tx.RctSignature.Get_Sig_Type() == ringct.RCTTypeSimpleBulletproof || tx.RctSignature.Get_Sig_Type() == ringct.RCTTypeFullBulletproof {
   460  
   461  			                    if len(tx.RctSignature.ECdhInfo) != len(tx.Vout) ||len(tx.Vout) != len(tx.RctSignature.BulletSigs) {
   462  			                        return fmt.Errorf("Invalid Bulletproof signature in Transaction\n")
   463  			                    }
   464  			                    for  i := range tx.RctSignature.ECdhInfo {
   465  			                        tx.RctSignature.BulletSigs[i].V = []crypto.Key{ crypto.Key(tx.RctSignature.OutPk[i].Mask) }
   466  
   467  			                        fmt.Printf("verifying BP now  \t ")
   468  
   469  			                        if tx.RctSignature.BulletSigs[i].BULLETPROOF_Verify() {
   470  			                         fmt.Printf("Bulletproof verification done successfully")
   471  			                        }else{
   472  			                            fmt.Printf("Bulletproof verification failed %+v \n", tx.RctSignature.BulletSigs[i])
   473  			                        }
   474  			                    }
   475  
   476  
   477  			                }*/
   478  
   479  	default:
   480  		return fmt.Errorf("Version 1 is NOT supported\n")
   481  	}
   482  
   483  	/* we must deserialize signature some where else
   484  
   485  
   486  
   487  
   488  	   //fmt.Printf("extra bytes %x\n",buf)
   489  
   490  	   //fmt.Printf("signature len %d  should be %d\n",len(buf),len(tx.Vin)*SIGNATURE_V1_LENGTH)
   491  	   fmt.Printf("signature len %d  should be %d\n",len(buf),Key_offset_count*SIGNATURE_V1_LENGTH)
   492  
   493  
   494  
   495  	   switch tx.Version {
   496  	       case 1 : // old style signatures, load value
   497  	                for i := uint64(0); i < Key_offset_count;i++{
   498  	                    var s Signature_v1
   499  	                    copy(s.R[:],buf[:32])
   500  	                    copy(s.C[:],buf[32:64])
   501  	                    tx.Signature = append(tx.Signature, s)
   502  	                    buf = buf[SIGNATURE_V1_LENGTH:]
   503  	                }
   504  	       case 2:
   505  	                tx.Signature_RCT.Type, done = binary.Uvarint(buf)
   506  	               if done <= 0 {
   507  	                       return fmt.Errorf("Invalid RCT signature in Transaction\n")
   508  	               }
   509  	                   buf = buf[done:]
   510  
   511  	                   switch tx.Signature_RCT.Type {
   512  
   513  	                       case 0 : // no signature break
   514  
   515  	                       case 1 :
   516  
   517  
   518  
   519  	                   tx.Signature_RCT.TxnFee, done = binary.Uvarint(buf)
   520  	               if done <= 0 {
   521  	                       return fmt.Errorf("Invalid txn fee in Transaction\n")
   522  	               }
   523  	                   buf = buf[done:]
   524  
   525  	                   fmt.Printf("RCT signature type %d  Fee %d\n",tx.Signature_RCT.Type, tx.Signature_RCT.TxnFee)
   526  
   527  
   528  	                   // how many masked inputs depends on number of masked outouts
   529  	                   for i := (0); i < len(tx.Vout);i++{
   530  	                       // read masked input
   531  	                       var info ECDHinfo
   532  	                       copy(info.Mask[:], buf[0:32])
   533  	                       copy(info.Amount[:], buf[32:64])
   534  	                       tx.Signature_RCT.Amounts = append(tx.Signature_RCT.Amounts, info)
   535  	                      buf = buf[64:]
   536  	                   }
   537  
   538  	                   // now parse the public keys
   539  	                   for i := (0); i < len(tx.Vout);i++{
   540  	                       // read masked input
   541  	                       var tmp [32]byte
   542  	                       copy(tmp[:], buf[0:32])
   543  
   544  	                       tx.Signature_RCT.OutPK = append(tx.Signature_RCT.OutPK, tmp)
   545  	                      buf = buf[32:]
   546  	                   }
   547  
   548  	                       case 2 : // panic("ringct type 2 currently not handled")
   549  
   550  
   551  	                       default:
   552  	                           panic("unknown signature style")
   553  
   554  
   555  	                   }
   556  
   557  	       default:
   558  	           panic("unknown transaction version \n")
   559  
   560  
   561  
   562  	   }
   563  
   564  
   565  	*/
   566  
   567  	rlog.Tracef(8, "TX deserialized %+v\n", tx)
   568  
   569  	/*
   570  		data.Local_time = binary.LittleEndian.Uint64( buf[24:], )
   571  
   572  		 data.Local_Port = binary.LittleEndian.Uint32( buf[41:])
   573  
   574  		_ = data.Network_UUID.UnmarshalBinary(buf[58:58+16])
   575  
   576  
   577  		data.Peer_ID = binary.LittleEndian.Uint64( buf[83:] )
   578  	*/
   579  	return nil //fmt.Errorf("Done Transaction\n")
   580  
   581  }
   582  
   583  // calculated prefi has signature
   584  func (tx *Transaction) Clear() {
   585  	// clean the transaction everything
   586  	tx.Version = 0
   587  	tx.Unlock_Time = 0
   588  	tx.Vin = tx.Vin[:0]
   589  	tx.Vout = tx.Vout[:0]
   590  	tx.Extra = tx.Extra[:0]
   591  
   592  }
   593  
   594  func (tx *Transaction) SerializeHeader() []byte {
   595  
   596  	var serialised_header bytes.Buffer
   597  
   598  	buf := make([]byte, binary.MaxVarintLen64)
   599  
   600  	n := binary.PutUvarint(buf, tx.Version)
   601  	serialised_header.Write(buf[:n])
   602  
   603  	n = binary.PutUvarint(buf, tx.Unlock_Time)
   604  	serialised_header.Write(buf[:n])
   605  
   606  	if len(tx.Vin) < 1 {
   607  		panic("No vins")
   608  	}
   609  
   610  	n = binary.PutUvarint(buf, uint64(len(tx.Vin)))
   611  	serialised_header.Write(buf[:n])
   612  
   613  	for _, current_vin := range tx.Vin {
   614  		switch current_vin.(type) {
   615  		case Txin_gen:
   616  			serialised_header.WriteByte(TXIN_GEN)
   617  			n = binary.PutUvarint(buf, current_vin.(Txin_gen).Height)
   618  			serialised_header.Write(buf[:n])
   619  
   620  		case Txin_to_key:
   621  			serialised_header.WriteByte(TXIN_TO_KEY)
   622  			n = binary.PutUvarint(buf, current_vin.(Txin_to_key).Amount)
   623  			serialised_header.Write(buf[:n])
   624  
   625  			// number of Ring member
   626  			n = binary.PutUvarint(buf, uint64(len(current_vin.(Txin_to_key).Key_offsets)))
   627  			serialised_header.Write(buf[:n])
   628  
   629  			// write ring members
   630  			for _, offset := range current_vin.(Txin_to_key).Key_offsets {
   631  				n = binary.PutUvarint(buf, offset)
   632  				serialised_header.Write(buf[:n])
   633  
   634  			}
   635  
   636  			// dump key image, interface needs a concrete type feor accessing array
   637  			cvin := current_vin.(Txin_to_key)
   638  			serialised_header.Write(cvin.K_image[:])
   639  
   640  		}
   641  	}
   642  
   643  	// time to serialize vouts
   644  
   645  	if len(tx.Vout) < 1 {
   646  		panic("No vout")
   647  	}
   648  
   649  	n = binary.PutUvarint(buf, uint64(len(tx.Vout)))
   650  	serialised_header.Write(buf[:n])
   651  
   652  	for _, current_vout := range tx.Vout {
   653  
   654  		// dump amount
   655  		n := binary.PutUvarint(buf, current_vout.Amount)
   656  		serialised_header.Write(buf[:n])
   657  
   658  		switch current_vout.Target.(type) {
   659  		case Txout_to_key:
   660  
   661  			serialised_header.WriteByte(TXOUT_TO_KEY)
   662  
   663  			target := current_vout.Target.(Txout_to_key)
   664  			serialised_header.Write(target.Key[:])
   665  
   666  			//serialised_header.Write(current_vout.Target.(Txout_to_key).Key[:])
   667  
   668  		default:
   669  			panic("This type of Txout not suppported")
   670  
   671  		}
   672  	}
   673  
   674  	// dump any extras
   675  	n = binary.PutUvarint(buf, uint64(len(tx.Extra)))
   676  	serialised_header.Write(buf[:n])
   677  
   678  	//rlog.Tracef("Extra length %d while serializing\n ", len(tx.Extra))
   679  
   680  	serialised_header.Write(tx.Extra[:])
   681  
   682  	return serialised_header.Bytes()
   683  
   684  }
   685  
   686  // serialize entire transaction include signature
   687  func (tx *Transaction) Serialize() []byte {
   688  
   689  	header_bytes := tx.SerializeHeader()
   690  	base_bytes := tx.RctSignature.SerializeBase()
   691  	prunable := tx.RctSignature.SerializePrunable()
   692  
   693  	buf := append(header_bytes, base_bytes...)
   694  	buf = append(buf, prunable...)
   695  
   696  	return buf
   697  
   698  }
   699  
   700  /*
   701  
   702  func (tx *Transaction) IsCoinbase() (result bool){
   703  
   704    // check whether the type is Txin.get
   705  
   706     if len(tx.Vin) != 0 { // coinbase transactions have no vin
   707      return
   708     }
   709  
   710     if tx.Vout[0].(Target) != 0 { // coinbase transactions have no vin
   711      return
   712     }
   713  
   714  
   715  }*/