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 }