git.gammaspectra.live/P2Pool/consensus@v0.0.0-20240403173234-a039820b20c9/monero/transaction/output.go (about)

     1  package transaction
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"fmt"
     7  	"git.gammaspectra.live/P2Pool/consensus/monero/crypto"
     8  	"git.gammaspectra.live/P2Pool/consensus/utils"
     9  	"io"
    10  )
    11  
    12  type Outputs []Output
    13  
    14  func (s *Outputs) FromReader(reader utils.ReaderAndByteReader) (err error) {
    15  	var outputCount uint64
    16  
    17  	if outputCount, err = binary.ReadUvarint(reader); err != nil {
    18  		return err
    19  	}
    20  
    21  	if outputCount > 0 {
    22  		if outputCount < 8192 {
    23  			*s = make(Outputs, 0, outputCount)
    24  		}
    25  
    26  		var o Output
    27  		for index := 0; index < int(outputCount); index++ {
    28  			o.Index = uint64(index)
    29  
    30  			if o.Reward, err = binary.ReadUvarint(reader); err != nil {
    31  				return err
    32  			}
    33  
    34  			if o.Type, err = reader.ReadByte(); err != nil {
    35  				return err
    36  			}
    37  
    38  			switch o.Type {
    39  			case TxOutToTaggedKey, TxOutToKey:
    40  				if _, err = io.ReadFull(reader, o.EphemeralPublicKey[:]); err != nil {
    41  					return err
    42  				}
    43  
    44  				if o.Type == TxOutToTaggedKey {
    45  					if o.ViewTag, err = reader.ReadByte(); err != nil {
    46  						return err
    47  					}
    48  				} else {
    49  					o.ViewTag = 0
    50  				}
    51  			default:
    52  				return fmt.Errorf("unknown %d TXOUT key", o.Type)
    53  			}
    54  
    55  			*s = append(*s, o)
    56  		}
    57  	}
    58  	return nil
    59  }
    60  
    61  func (s *Outputs) BufferLength() (n int) {
    62  	n = utils.UVarInt64Size(len(*s))
    63  	for _, o := range *s {
    64  		n += utils.UVarInt64Size(o.Reward) +
    65  			1 +
    66  			crypto.PublicKeySize
    67  		if o.Type == TxOutToTaggedKey {
    68  			n++
    69  		}
    70  	}
    71  	return n
    72  }
    73  
    74  func (s *Outputs) MarshalBinary() (data []byte, err error) {
    75  	return s.AppendBinary(make([]byte, 0, s.BufferLength()))
    76  }
    77  
    78  func (s *Outputs) AppendBinary(preAllocatedBuf []byte) (data []byte, err error) {
    79  	data = preAllocatedBuf
    80  
    81  	data = binary.AppendUvarint(data, uint64(len(*s)))
    82  
    83  	for _, o := range *s {
    84  		data = binary.AppendUvarint(data, o.Reward)
    85  		data = append(data, o.Type)
    86  
    87  		switch o.Type {
    88  		case TxOutToTaggedKey, TxOutToKey:
    89  			data = append(data, o.EphemeralPublicKey[:]...)
    90  
    91  			if o.Type == TxOutToTaggedKey {
    92  				data = append(data, o.ViewTag)
    93  			}
    94  		default:
    95  			return nil, errors.New("unknown output type")
    96  		}
    97  	}
    98  	return data, nil
    99  }
   100  
   101  type Output struct {
   102  	Index  uint64 `json:"index"`
   103  	Reward uint64 `json:"reward"`
   104  	// Type would be here
   105  	EphemeralPublicKey crypto.PublicKeyBytes `json:"ephemeral_public_key"`
   106  	// Type re-arranged here to improve memory layout space
   107  	Type    uint8 `json:"type"`
   108  	ViewTag uint8 `json:"view_tag"`
   109  }