// Copyright 2017-2018 DERO Project. All rights reserved.
|
|
// Use of this source code in any form is governed by RESEARCH license.
|
|
// license can be found in the LICENSE file.
|
|
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
|
|
//
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
package transaction
|
|
|
|
import "fmt"
|
|
import "bytes"
|
|
import "encoding/binary"
|
|
|
|
import "github.com/romana/rlog"
|
|
|
|
import "github.com/deroproject/derosuite/crypto"
|
|
import "github.com/deroproject/derosuite/crypto/ringct"
|
|
|
|
const TXIN_GEN = byte(0xff)
|
|
const TXIN_TO_SCRIPT = byte(0)
|
|
const TXIN_TO_SCRIPTHASH = byte(1)
|
|
const TXIN_TO_KEY = byte(2)
|
|
|
|
const TXOUT_TO_SCRIPT = byte(0)
|
|
const TXOUT_TO_SCRIPTHASH = byte(1)
|
|
const TXOUT_TO_KEY = byte(2)
|
|
|
|
var TX_IN_NAME = map[byte]string{
|
|
TXIN_GEN: "Coinbase",
|
|
TXIN_TO_SCRIPT: "To Script",
|
|
TXIN_TO_SCRIPTHASH: "To Script hash",
|
|
TXIN_TO_KEY: "To key",
|
|
}
|
|
|
|
const TRANSACTION = byte(0xcc)
|
|
const BLOCK = byte(0xbb)
|
|
|
|
/*
|
|
VARIANT_TAG(binary_archive, cryptonote::txin_to_script, 0x0);
|
|
VARIANT_TAG(binary_archive, cryptonote::txin_to_scripthash, 0x1);
|
|
VARIANT_TAG(binary_archive, cryptonote::txin_to_key, 0x2);
|
|
VARIANT_TAG(binary_archive, cryptonote::txout_to_script, 0x0);
|
|
VARIANT_TAG(binary_archive, cryptonote::txout_to_scripthash, 0x1);
|
|
VARIANT_TAG(binary_archive, cryptonote::txout_to_key, 0x2);
|
|
VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc);
|
|
VARIANT_TAG(binary_archive, cryptonote::block, 0xbb);
|
|
*/
|
|
/* outputs */
|
|
|
|
type Txout_to_script struct {
|
|
// std::vector<crypto::public_key> keys;
|
|
// std::vector<uint8_t> script;
|
|
|
|
Keys [][32]byte
|
|
Script []byte
|
|
|
|
/* BEGIN_SERIALIZE_OBJECT()
|
|
FIELD(keys)
|
|
FIELD(script)
|
|
END_SERIALIZE()
|
|
|
|
*/
|
|
}
|
|
|
|
type Txout_to_scripthash struct {
|
|
//crypto::hash hash;
|
|
Hash [32]byte
|
|
}
|
|
|
|
type Txout_to_key struct {
|
|
Key crypto.Key
|
|
// Mask [32]byte `json:"-"`
|
|
/*txout_to_key() { }
|
|
txout_to_key(const crypto::public_key &_key) : key(_key) { }
|
|
crypto::public_key key;*/
|
|
|
|
}
|
|
|
|
// there can be only 4 types if inputs
|
|
|
|
// used by miner
|
|
type Txin_gen struct {
|
|
Height uint64 // stored as varint
|
|
}
|
|
|
|
type Txin_to_script struct {
|
|
Prev [32]byte
|
|
Prevout uint64
|
|
Sigset []byte
|
|
|
|
/* BEGIN_SERIALIZE_OBJECT()
|
|
FIELD(prev)
|
|
VARINT_FIELD(prevout)
|
|
FIELD(sigset)
|
|
END_SERIALIZE()
|
|
*/
|
|
}
|
|
|
|
type Txin_to_scripthash struct {
|
|
Prev [32]byte
|
|
Prevout uint64
|
|
Script Txout_to_script
|
|
Sigset []byte
|
|
|
|
/* BEGIN_SERIALIZE_OBJECT()
|
|
FIELD(prev)
|
|
VARINT_FIELD(prevout)
|
|
FIELD(script)
|
|
FIELD(sigset)
|
|
END_SERIALIZE()
|
|
*/
|
|
}
|
|
|
|
type Txin_to_key struct {
|
|
Amount uint64
|
|
Key_offsets []uint64 // this is encoded as a varint for length and then all offsets are stored as varint
|
|
//crypto::key_image k_image; // double spending protection
|
|
K_image crypto.Hash `json:"k_image"` // key image
|
|
|
|
/* BEGIN_SERIALIZE_OBJECT()
|
|
VARINT_FIELD(amount)
|
|
FIELD(key_offsets)
|
|
FIELD(k_image)
|
|
END_SERIALIZE()
|
|
*/
|
|
}
|
|
|
|
type Txin_v interface{} // it can only be txin_gen, txin_to_script, txin_to_scripthash, txin_to_key
|
|
|
|
type Tx_out struct {
|
|
Amount uint64
|
|
Target interface{} // txout_target_v ;, it can only be txout_to_script, txout_to_scripthash, txout_to_key
|
|
|
|
/* BEGIN_SERIALIZE_OBJECT()
|
|
VARINT_FIELD(amount)
|
|
FIELD(target)
|
|
END_SERIALIZE()
|
|
*/
|
|
|
|
}
|
|
|
|
// the core transaction
|
|
type Transaction_Prefix struct {
|
|
Version uint64 `json:"version"`
|
|
Unlock_Time uint64 `json:"unlock_time"` // used to lock first output
|
|
Vin []Txin_v
|
|
Vout []Tx_out
|
|
Extra []byte
|
|
Extra_map map[EXTRA_TAG]interface{} `json:"-"` // all information parsed from extra is placed here
|
|
PaymentID_map map[EXTRA_TAG]interface{} `json:"-"` // payments id parsed or set are placed her
|
|
ExtraType byte `json:"-"` // NOT used, candidate for deletion
|
|
}
|
|
|
|
type Transaction struct {
|
|
Transaction_Prefix
|
|
// same as Transaction_Prefix
|
|
// Signature not sure of what form
|
|
Signature []Signature_v1 `json:"-"` // old format, the array size is always equal to vin length,
|
|
//Signature_RCT RCT_Signature // version 2
|
|
|
|
RctSignature *ringct.RctSig
|
|
Expanded bool `json:"-"`
|
|
}
|
|
|
|
func (tx *Transaction) GetHash() (result crypto.Hash) {
|
|
switch tx.Version {
|
|
|
|
case 1:
|
|
result = crypto.Hash(crypto.Keccak256(tx.SerializeHeader()))
|
|
|
|
case 2:
|
|
// version 2 requires first computing 3 separate hashes
|
|
// prefix, rctBase and rctPrunable
|
|
// and then hashing the hashes together to get the final hash
|
|
prefixHash := tx.GetPrefixHash()
|
|
rctBaseHash := tx.RctSignature.BaseHash()
|
|
rctPrunableHash := tx.RctSignature.PrunableHash()
|
|
result = crypto.Hash(crypto.Keccak256(prefixHash[:], rctBaseHash[:], rctPrunableHash[:]))
|
|
default:
|
|
panic("Transaction version cannot be zero")
|
|
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (tx *Transaction) GetPrefixHash() (result crypto.Hash) {
|
|
result = crypto.Keccak256(tx.SerializeHeader())
|
|
return result
|
|
}
|
|
|
|
// returns whether the tx is coinbase
|
|
func (tx *Transaction) IsCoinbase() (result bool) {
|
|
switch tx.Vin[0].(type) {
|
|
case Txin_gen:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (tx *Transaction) DeserializeHeader(buf []byte) (err error) {
|
|
|
|
Key_offset_count := uint64(0) // used to calculate expected signatures in v1
|
|
|
|
Mixin := -1
|
|
|
|
tx.Clear() // clear existing
|
|
|
|
//Mixin_count := 0 // for signature purpose
|
|
|
|
done := 0
|
|
tx.Version, done = binary.Uvarint(buf)
|
|
if done <= 0 {
|
|
return fmt.Errorf("Invalid Version in Transaction\n")
|
|
}
|
|
|
|
rlog.Tracef(10, "transaction version %d\n", tx.Version)
|
|
|
|
buf = buf[done:]
|
|
tx.Unlock_Time, done = binary.Uvarint(buf)
|
|
if done <= 0 {
|
|
return fmt.Errorf("Invalid Unlock_Time in Transaction\n")
|
|
}
|
|
buf = buf[done:]
|
|
|
|
// parse vin length
|
|
vin_length, done := binary.Uvarint(buf)
|
|
if done <= 0 {
|
|
return fmt.Errorf("Invalid Vin length in Transaction\n")
|
|
}
|
|
buf = buf[done:]
|
|
|
|
if vin_length == 0 {
|
|
return fmt.Errorf("Vin input cannot be zero in Transaction\n")
|
|
|
|
}
|
|
|
|
coinbase_done := false
|
|
|
|
rlog.Tracef(10, "vin length %d\n", vin_length)
|
|
|
|
for i := uint64(0); i < vin_length; i++ {
|
|
|
|
vin_type := buf[0]
|
|
|
|
buf = buf[1:] // consume 1 more byte
|
|
|
|
rlog.Tracef(10, "Processing i %d vin_type %s hex %x\n", i, TX_IN_NAME[vin_type], buf[:40])
|
|
|
|
switch vin_type {
|
|
case TXIN_GEN:
|
|
rlog.Tracef(10, "Coinbase transaction\n")
|
|
|
|
if coinbase_done {
|
|
return fmt.Errorf("Transaction cannot have multiple coin base transaction\n")
|
|
|
|
}
|
|
var current_vin Txin_gen
|
|
current_vin.Height, done = binary.Uvarint(buf)
|
|
if done <= 0 {
|
|
return fmt.Errorf("Invalid Height for Txin_gen vin in Transaction\n")
|
|
}
|
|
buf = buf[done:]
|
|
tx.Vin = append(tx.Vin, current_vin)
|
|
|
|
coinbase_done = true // we can no longer have coin base
|
|
|
|
case TXIN_TO_SCRIPT:
|
|
panic("TXIN_TO_SCRIPT not implemented")
|
|
case TXIN_TO_SCRIPTHASH:
|
|
panic("TXIN_TO_SCRIPTHASH not implemented")
|
|
case TXIN_TO_KEY:
|
|
var current_vin Txin_to_key
|
|
|
|
// parse Amount
|
|
current_vin.Amount, done = binary.Uvarint(buf)
|
|
if done <= 0 {
|
|
return fmt.Errorf("Invalid Amount for Txin_to_key vin in Transaction\n")
|
|
}
|
|
buf = buf[done:]
|
|
|
|
//fmt.Printf("Remaining data %x\n", buf[:20]);
|
|
|
|
mixin_count, done := binary.Uvarint(buf)
|
|
if done <= 0 {
|
|
return fmt.Errorf("Invalid offset_count for Txin_to_key vin in Transaction\n")
|
|
}
|
|
buf = buf[done:]
|
|
|
|
// safety check mixin cannot be larger than say x
|
|
|
|
if mixin_count > 400 {
|
|
return fmt.Errorf("Mixin cannot be larger than 400\n")
|
|
}
|
|
|
|
if Mixin < 0 {
|
|
Mixin = int(mixin_count)
|
|
}
|
|
|
|
if Mixin != int(mixin_count) { // all vins must have same mixin
|
|
return fmt.Errorf("Different mixin in Transaction\n")
|
|
|
|
}
|
|
|
|
//Mixin_input_count += Mixin
|
|
|
|
for j := uint64(0); j < mixin_count; j++ {
|
|
offset, done := binary.Uvarint(buf)
|
|
if done <= 0 {
|
|
return fmt.Errorf("Invalid key offset for Txin_to_key vin in Transaction\n")
|
|
}
|
|
buf = buf[done:]
|
|
current_vin.Key_offsets = append(current_vin.Key_offsets, offset)
|
|
}
|
|
|
|
Key_offset_count += mixin_count
|
|
|
|
copy(current_vin.K_image[:], buf[:32]) // copy key image
|
|
|
|
buf = buf[32:] // consume key image bytes
|
|
|
|
tx.Vin = append(tx.Vin, current_vin)
|
|
|
|
// panic("TXIN_TO_KEY not implemented")
|
|
|
|
default:
|
|
panic("Invalid VIN type in Transaction")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//fmt.Printf("TX before vout %+v\n", tx)
|
|
|
|
//fmt.Printf("buf before vout length %x\n", buf)
|
|
vout_length, done := binary.Uvarint(buf)
|
|
if done <= 0 {
|
|
return fmt.Errorf("Invalid Vout length in Transaction\n")
|
|
}
|
|
buf = buf[done:]
|
|
|
|
if vout_length == 0 {
|
|
return fmt.Errorf("Vout cannot be zero in Transaction\n")
|
|
}
|
|
|
|
for i := uint64(0); i < vout_length; i++ {
|
|
|
|
// amount is decoded earlier
|
|
|
|
amount, done := binary.Uvarint(buf)
|
|
if done <= 0 {
|
|
return fmt.Errorf("Invalid Amount in Transaction\n")
|
|
}
|
|
buf = buf[done:]
|
|
|
|
// decode vout type
|
|
|
|
vout_type := buf[0]
|
|
buf = buf[1:] // consume 1 more byte
|
|
|
|
rlog.Tracef(10, "Vout Amount length %d vout type %d \n", amount, vout_type)
|
|
|
|
if tx.Version == 1 && amount == 0 { // version 2 can have any amount
|
|
return fmt.Errorf("Amount cannot be zero in Transaction\n")
|
|
}
|
|
switch vout_type {
|
|
case TXOUT_TO_SCRIPT:
|
|
//fmt.Printf("out to script\n")
|
|
panic("TXOUT_TO_SCRIPT not implemented")
|
|
case TXOUT_TO_SCRIPTHASH:
|
|
//fmt.Printf("out to scripthash\n")
|
|
var current_vout Txout_to_scripthash
|
|
copy(current_vout.Hash[:], buf[0:32])
|
|
tx.Vout = append(tx.Vout, Tx_out{Amount: amount, Target: current_vout})
|
|
|
|
buf = buf[32:]
|
|
|
|
//panic("TXOUT_TO_SCRIPTHASH not implemented")
|
|
case TXOUT_TO_KEY:
|
|
//fmt.Printf("out to key\n")
|
|
|
|
var current_vout Txout_to_key
|
|
|
|
copy(current_vout.Key[:], buf[0:32])
|
|
buf = buf[32:]
|
|
|
|
//Mixin_input_count++
|
|
|
|
tx.Vout = append(tx.Vout, Tx_out{Amount: amount, Target: current_vout})
|
|
|
|
default:
|
|
return fmt.Errorf("Invalid VOUT type in Transaction\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// fmt.Printf("Extra %x\n", buf)
|
|
// decode extra
|
|
extra_length, done := binary.Uvarint(buf)
|
|
if done <= 0 {
|
|
return fmt.Errorf("Invalid Extra length in Transaction\n")
|
|
}
|
|
buf = buf[done:]
|
|
|
|
// BUG extra needs to be processed in a loop till we load all extra fields
|
|
|
|
//tx.ExtraType = buf[0]
|
|
// buf = buf[1:] // consume 1 more byte
|
|
|
|
// extra_length--
|
|
|
|
rlog.Tracef(8, "extra len %d have %d \n", extra_length, len(buf))
|
|
tx.Extra = buf[:extra_length]
|
|
|
|
// whatever is leftover is signature
|
|
buf = buf[extra_length:] // consume more bytes
|
|
|
|
switch tx.Version {
|
|
case 1: // old style signatures, load value
|
|
for i := uint64(0); i < Key_offset_count; i++ {
|
|
var s Signature_v1
|
|
copy(s.R[:], buf[:32])
|
|
copy(s.C[:], buf[32:64])
|
|
tx.Signature = append(tx.Signature, s)
|
|
buf = buf[SIGNATURE_V1_LENGTH:]
|
|
}
|
|
case 2:
|
|
bufreader := bytes.NewReader(buf)
|
|
|
|
Mixin -= 1 // one is ours, rest are mixin
|
|
|
|
tx.RctSignature, err = ringct.ParseRingCtSignature(bufreader, len(tx.Vin), len(tx.Vout), Mixin)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
/* we must deserialize signature some where else
|
|
|
|
|
|
|
|
|
|
//fmt.Printf("extra bytes %x\n",buf)
|
|
|
|
//fmt.Printf("signature len %d should be %d\n",len(buf),len(tx.Vin)*SIGNATURE_V1_LENGTH)
|
|
fmt.Printf("signature len %d should be %d\n",len(buf),Key_offset_count*SIGNATURE_V1_LENGTH)
|
|
|
|
|
|
|
|
switch tx.Version {
|
|
case 1 : // old style signatures, load value
|
|
for i := uint64(0); i < Key_offset_count;i++{
|
|
var s Signature_v1
|
|
copy(s.R[:],buf[:32])
|
|
copy(s.C[:],buf[32:64])
|
|
tx.Signature = append(tx.Signature, s)
|
|
buf = buf[SIGNATURE_V1_LENGTH:]
|
|
}
|
|
case 2:
|
|
tx.Signature_RCT.Type, done = binary.Uvarint(buf)
|
|
if done <= 0 {
|
|
return fmt.Errorf("Invalid RCT signature in Transaction\n")
|
|
}
|
|
buf = buf[done:]
|
|
|
|
switch tx.Signature_RCT.Type {
|
|
|
|
case 0 : // no signature break
|
|
|
|
case 1 :
|
|
|
|
|
|
|
|
tx.Signature_RCT.TxnFee, done = binary.Uvarint(buf)
|
|
if done <= 0 {
|
|
return fmt.Errorf("Invalid txn fee in Transaction\n")
|
|
}
|
|
buf = buf[done:]
|
|
|
|
fmt.Printf("RCT signature type %d Fee %d\n",tx.Signature_RCT.Type, tx.Signature_RCT.TxnFee)
|
|
|
|
|
|
// how many masked inputs depends on number of masked outouts
|
|
for i := (0); i < len(tx.Vout);i++{
|
|
// read masked input
|
|
var info ECDHinfo
|
|
copy(info.Mask[:], buf[0:32])
|
|
copy(info.Amount[:], buf[32:64])
|
|
tx.Signature_RCT.Amounts = append(tx.Signature_RCT.Amounts, info)
|
|
buf = buf[64:]
|
|
}
|
|
|
|
// now parse the public keys
|
|
for i := (0); i < len(tx.Vout);i++{
|
|
// read masked input
|
|
var tmp [32]byte
|
|
copy(tmp[:], buf[0:32])
|
|
|
|
tx.Signature_RCT.OutPK = append(tx.Signature_RCT.OutPK, tmp)
|
|
buf = buf[32:]
|
|
}
|
|
|
|
case 2 : // panic("ringct type 2 currently not handled")
|
|
|
|
|
|
default:
|
|
panic("unknown signature style")
|
|
|
|
|
|
}
|
|
|
|
default:
|
|
panic("unknown transaction version \n")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
*/
|
|
|
|
rlog.Tracef(8, "TX deserialized %+v\n", tx)
|
|
|
|
/*
|
|
data.Local_time = binary.LittleEndian.Uint64( buf[24:], )
|
|
|
|
data.Local_Port = binary.LittleEndian.Uint32( buf[41:])
|
|
|
|
_ = data.Network_UUID.UnmarshalBinary(buf[58:58+16])
|
|
|
|
|
|
data.Peer_ID = binary.LittleEndian.Uint64( buf[83:] )
|
|
*/
|
|
return nil //fmt.Errorf("Done Transaction\n")
|
|
|
|
}
|
|
|
|
// calculated prefi has signature
|
|
func (tx *Transaction) PrefixHash() {
|
|
|
|
}
|
|
|
|
// calculated prefi has signature
|
|
func (tx *Transaction) Clear() {
|
|
// clean the transaction everything
|
|
tx.Version = 0
|
|
tx.Unlock_Time = 0
|
|
tx.Vin = tx.Vin[:0]
|
|
tx.Vout = tx.Vout[:0]
|
|
tx.Extra = tx.Extra[:0]
|
|
|
|
}
|
|
|
|
func (tx *Transaction) SerializeHeader() []byte {
|
|
|
|
var serialised_header bytes.Buffer
|
|
|
|
buf := make([]byte, binary.MaxVarintLen64)
|
|
|
|
n := binary.PutUvarint(buf, tx.Version)
|
|
serialised_header.Write(buf[:n])
|
|
|
|
n = binary.PutUvarint(buf, tx.Unlock_Time)
|
|
serialised_header.Write(buf[:n])
|
|
|
|
/*if len(tx.Vin) < 1 {
|
|
panic("No vins")
|
|
}*/
|
|
|
|
n = binary.PutUvarint(buf, uint64(len(tx.Vin)))
|
|
serialised_header.Write(buf[:n])
|
|
|
|
for _, current_vin := range tx.Vin {
|
|
switch current_vin.(type) {
|
|
case Txin_gen:
|
|
serialised_header.WriteByte(TXIN_GEN)
|
|
n = binary.PutUvarint(buf, current_vin.(Txin_gen).Height)
|
|
serialised_header.Write(buf[:n])
|
|
|
|
case Txin_to_key:
|
|
serialised_header.WriteByte(TXIN_TO_KEY)
|
|
n = binary.PutUvarint(buf, current_vin.(Txin_to_key).Amount)
|
|
serialised_header.Write(buf[:n])
|
|
|
|
// number of Ring member
|
|
n = binary.PutUvarint(buf, uint64(len(current_vin.(Txin_to_key).Key_offsets)))
|
|
serialised_header.Write(buf[:n])
|
|
|
|
// write ring members
|
|
for _, offset := range current_vin.(Txin_to_key).Key_offsets {
|
|
n = binary.PutUvarint(buf, offset)
|
|
serialised_header.Write(buf[:n])
|
|
|
|
}
|
|
|
|
// dump key image, interface needs a concrete type feor accessing array
|
|
cvin := current_vin.(Txin_to_key)
|
|
serialised_header.Write(cvin.K_image[:])
|
|
|
|
}
|
|
}
|
|
|
|
// time to serialize vouts
|
|
|
|
if len(tx.Vout) < 1 {
|
|
panic("No vout")
|
|
}
|
|
|
|
n = binary.PutUvarint(buf, uint64(len(tx.Vout)))
|
|
serialised_header.Write(buf[:n])
|
|
|
|
for _, current_vout := range tx.Vout {
|
|
|
|
// dump amount
|
|
n := binary.PutUvarint(buf, current_vout.Amount)
|
|
serialised_header.Write(buf[:n])
|
|
|
|
switch current_vout.Target.(type) {
|
|
case Txout_to_key:
|
|
|
|
serialised_header.WriteByte(TXOUT_TO_KEY)
|
|
|
|
target := current_vout.Target.(Txout_to_key)
|
|
serialised_header.Write(target.Key[:])
|
|
|
|
//serialised_header.Write(current_vout.Target.(Txout_to_key).Key[:])
|
|
|
|
default:
|
|
panic("This type of Txout not suppported")
|
|
|
|
}
|
|
}
|
|
|
|
// dump any extras
|
|
n = binary.PutUvarint(buf, uint64(len(tx.Extra)))
|
|
serialised_header.Write(buf[:n])
|
|
|
|
//rlog.Tracef("Extra length %d while serializing\n ", len(tx.Extra))
|
|
|
|
serialised_header.Write(tx.Extra[:])
|
|
|
|
return serialised_header.Bytes()
|
|
|
|
}
|
|
|
|
// serialize entire transaction include signature
|
|
func (tx *Transaction) Serialize() []byte {
|
|
|
|
header_bytes := tx.SerializeHeader()
|
|
base_bytes := tx.RctSignature.SerializeBase()
|
|
prunable := tx.RctSignature.SerializePrunable()
|
|
|
|
buf := append(header_bytes, base_bytes...)
|
|
buf = append(buf, prunable...)
|
|
|
|
return buf
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
func (tx *Transaction) IsCoinbase() (result bool){
|
|
|
|
// check whether the type is Txin.get
|
|
|
|
if len(tx.Vin) != 0 { // coinbase transactions have no vin
|
|
return
|
|
}
|
|
|
|
if tx.Vout[0].(Target) != 0 { // coinbase transactions have no vin
|
|
return
|
|
}
|
|
|
|
|
|
}*/
|