git.gammaspectra.live/P2Pool/consensus@v0.0.0-20240403173234-a039820b20c9/p2pool/sidechain/sidedata.go (about)

     1  package sidechain
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"git.gammaspectra.live/P2Pool/consensus/monero/address"
     8  	"git.gammaspectra.live/P2Pool/consensus/monero/crypto"
     9  	p2pooltypes "git.gammaspectra.live/P2Pool/consensus/p2pool/types"
    10  	"git.gammaspectra.live/P2Pool/consensus/types"
    11  	"git.gammaspectra.live/P2Pool/consensus/utils"
    12  	"io"
    13  )
    14  
    15  type SideData struct {
    16  	PublicKey              address.PackedAddress `json:"public_key"`
    17  	CoinbasePrivateKeySeed types.Hash            `json:"coinbase_private_key_seed,omitempty"`
    18  	// CoinbasePrivateKey filled or calculated on decoding
    19  	CoinbasePrivateKey   crypto.PrivateKeyBytes `json:"coinbase_private_key"`
    20  	Parent               types.Hash             `json:"parent"`
    21  	Uncles               []types.Hash           `json:"uncles,omitempty"`
    22  	Height               uint64                 `json:"height"`
    23  	Difficulty           types.Difficulty       `json:"difficulty"`
    24  	CumulativeDifficulty types.Difficulty       `json:"cumulative_difficulty"`
    25  
    26  	// ExtraBuffer available in ShareVersion ShareVersion_V2 and above
    27  	ExtraBuffer struct {
    28  		SoftwareId          p2pooltypes.SoftwareId      `json:"software_id"`
    29  		SoftwareVersion     p2pooltypes.SoftwareVersion `json:"software_version"`
    30  		RandomNumber        uint32                      `json:"random_number"`
    31  		SideChainExtraNonce uint32                      `json:"side_chain_extra_nonce"`
    32  	} `json:"extra_buffer,omitempty"`
    33  }
    34  
    35  func (b *SideData) BufferLength() int {
    36  	return crypto.PublicKeySize +
    37  		crypto.PublicKeySize +
    38  		types.HashSize +
    39  		crypto.PrivateKeySize +
    40  		utils.UVarInt64Size(len(b.Uncles)) + len(b.Uncles)*types.HashSize +
    41  		utils.UVarInt64Size(b.Height) +
    42  		utils.UVarInt64Size(b.Difficulty.Lo) + utils.UVarInt64Size(b.Difficulty.Hi) +
    43  		utils.UVarInt64Size(b.CumulativeDifficulty.Lo) + utils.UVarInt64Size(b.CumulativeDifficulty.Hi) +
    44  		4*4
    45  }
    46  
    47  func (b *SideData) MarshalBinary(version ShareVersion) (buf []byte, err error) {
    48  	return b.AppendBinary(make([]byte, 0, b.BufferLength()), version)
    49  }
    50  
    51  func (b *SideData) AppendBinary(preAllocatedBuf []byte, version ShareVersion) (buf []byte, err error) {
    52  	buf = preAllocatedBuf
    53  	buf = append(buf, b.PublicKey[address.PackedAddressSpend][:]...)
    54  	buf = append(buf, b.PublicKey[address.PackedAddressView][:]...)
    55  	if version > ShareVersion_V1 {
    56  		buf = append(buf, b.CoinbasePrivateKeySeed[:]...)
    57  	} else {
    58  		buf = append(buf, b.CoinbasePrivateKey[:]...)
    59  	}
    60  	buf = append(buf, b.Parent[:]...)
    61  	buf = binary.AppendUvarint(buf, uint64(len(b.Uncles)))
    62  	for _, uId := range b.Uncles {
    63  		buf = append(buf, uId[:]...)
    64  	}
    65  	buf = binary.AppendUvarint(buf, b.Height)
    66  	buf = binary.AppendUvarint(buf, b.Difficulty.Lo)
    67  	buf = binary.AppendUvarint(buf, b.Difficulty.Hi)
    68  	buf = binary.AppendUvarint(buf, b.CumulativeDifficulty.Lo)
    69  	buf = binary.AppendUvarint(buf, b.CumulativeDifficulty.Hi)
    70  	if version > ShareVersion_V1 {
    71  		buf = binary.LittleEndian.AppendUint32(buf, uint32(b.ExtraBuffer.SoftwareId))
    72  		buf = binary.LittleEndian.AppendUint32(buf, uint32(b.ExtraBuffer.SoftwareVersion))
    73  		buf = binary.LittleEndian.AppendUint32(buf, b.ExtraBuffer.RandomNumber)
    74  		buf = binary.LittleEndian.AppendUint32(buf, b.ExtraBuffer.SideChainExtraNonce)
    75  	}
    76  
    77  	return buf, nil
    78  }
    79  
    80  func (b *SideData) FromReader(reader utils.ReaderAndByteReader, version ShareVersion) (err error) {
    81  	var (
    82  		uncleCount uint64
    83  		uncleHash  types.Hash
    84  	)
    85  	if _, err = io.ReadFull(reader, b.PublicKey[address.PackedAddressSpend][:]); err != nil {
    86  		return err
    87  	}
    88  	if _, err = io.ReadFull(reader, b.PublicKey[address.PackedAddressView][:]); err != nil {
    89  		return err
    90  	}
    91  
    92  	if version > ShareVersion_V1 {
    93  		//needs preprocessing
    94  		if _, err = io.ReadFull(reader, b.CoinbasePrivateKeySeed[:]); err != nil {
    95  			return err
    96  		}
    97  	} else {
    98  		if _, err = io.ReadFull(reader, b.CoinbasePrivateKey[:]); err != nil {
    99  			return err
   100  		}
   101  	}
   102  	if _, err = io.ReadFull(reader, b.Parent[:]); err != nil {
   103  		return err
   104  	}
   105  	if uncleCount, err = binary.ReadUvarint(reader); err != nil {
   106  		return err
   107  	}
   108  
   109  	for i := 0; i < int(uncleCount); i++ {
   110  		if _, err = io.ReadFull(reader, uncleHash[:]); err != nil {
   111  			return err
   112  		}
   113  		//TODO: check if copy is needed
   114  		b.Uncles = append(b.Uncles, uncleHash)
   115  	}
   116  
   117  	if b.Height, err = binary.ReadUvarint(reader); err != nil {
   118  		return err
   119  	}
   120  
   121  	{
   122  		if b.Difficulty.Lo, err = binary.ReadUvarint(reader); err != nil {
   123  			return err
   124  		}
   125  
   126  		if b.Difficulty.Hi, err = binary.ReadUvarint(reader); err != nil {
   127  			return err
   128  		}
   129  	}
   130  
   131  	{
   132  		if b.CumulativeDifficulty.Lo, err = binary.ReadUvarint(reader); err != nil {
   133  			return err
   134  		}
   135  
   136  		if b.CumulativeDifficulty.Hi, err = binary.ReadUvarint(reader); err != nil {
   137  			return err
   138  		}
   139  	}
   140  	if version > ShareVersion_V1 {
   141  		if err = binary.Read(reader, binary.LittleEndian, &b.ExtraBuffer.SoftwareId); err != nil {
   142  			return fmt.Errorf("within extra buffer: %w", err)
   143  		}
   144  		if err = binary.Read(reader, binary.LittleEndian, &b.ExtraBuffer.SoftwareVersion); err != nil {
   145  			return fmt.Errorf("within extra buffer: %w", err)
   146  		}
   147  		if err = binary.Read(reader, binary.LittleEndian, &b.ExtraBuffer.RandomNumber); err != nil {
   148  			return fmt.Errorf("within extra buffer: %w", err)
   149  		}
   150  		if err = binary.Read(reader, binary.LittleEndian, &b.ExtraBuffer.SideChainExtraNonce); err != nil {
   151  			return fmt.Errorf("within extra buffer: %w", err)
   152  		}
   153  	}
   154  
   155  	return nil
   156  }
   157  
   158  func (b *SideData) UnmarshalBinary(data []byte, version ShareVersion) error {
   159  	reader := bytes.NewReader(data)
   160  	return b.FromReader(reader, version)
   161  }