git.gammaspectra.live/P2Pool/consensus/v3@v3.8.0/p2pool/stratum/template.go (about)

     1  package stratum
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"git.gammaspectra.live/P2Pool/consensus/v3/monero/crypto"
     7  	"git.gammaspectra.live/P2Pool/consensus/v3/p2pool/sidechain"
     8  	"git.gammaspectra.live/P2Pool/consensus/v3/types"
     9  	"git.gammaspectra.live/P2Pool/consensus/v3/utils"
    10  	"git.gammaspectra.live/P2Pool/sha3"
    11  	"io"
    12  )
    13  
    14  type Template struct {
    15  	Buffer []byte
    16  
    17  	// NonceOffset offset of an uint32
    18  	NonceOffset int
    19  
    20  	CoinbaseOffset int
    21  
    22  	// ExtraNonceOffset offset of an uint32
    23  	ExtraNonceOffset int
    24  
    25  	// TemplateIdOffset offset of a types.Hash
    26  	TemplateIdOffset int
    27  
    28  	// TransactionsOffset Start of transactions section
    29  	TransactionsOffset int
    30  
    31  	// TemplateExtraBufferOffset offset of 4*uint32
    32  	TemplateExtraBufferOffset int
    33  
    34  	MainHeight uint64
    35  	MainParent types.Hash
    36  
    37  	SideHeight     uint64
    38  	SideParent     types.Hash
    39  	SideDifficulty types.Difficulty
    40  
    41  	MerkleTreeMainBranch []types.Hash
    42  }
    43  
    44  func (tpl *Template) Write(writer io.Writer, nonce, extraNonce, sideRandomNumber, sideExtraNonce uint32, templateId types.Hash) error {
    45  	var uint32Buf [4]byte
    46  
    47  	if _, err := writer.Write(tpl.Buffer[:tpl.NonceOffset]); err != nil {
    48  		return err
    49  	}
    50  
    51  	binary.LittleEndian.PutUint32(uint32Buf[:], nonce)
    52  	if _, err := writer.Write(uint32Buf[:]); err != nil {
    53  		return err
    54  	}
    55  
    56  	if _, err := writer.Write(tpl.Buffer[tpl.NonceOffset+4 : tpl.ExtraNonceOffset]); err != nil {
    57  		return err
    58  	}
    59  
    60  	binary.LittleEndian.PutUint32(uint32Buf[:], extraNonce)
    61  	if _, err := writer.Write(uint32Buf[:]); err != nil {
    62  		return err
    63  	}
    64  
    65  	if _, err := writer.Write(tpl.Buffer[tpl.ExtraNonceOffset+4 : tpl.TemplateIdOffset]); err != nil {
    66  		return err
    67  	}
    68  	if _, err := writer.Write(templateId[:]); err != nil {
    69  		return err
    70  	}
    71  	if _, err := writer.Write(tpl.Buffer[tpl.TemplateIdOffset+types.HashSize : tpl.TemplateExtraBufferOffset+4*2]); err != nil {
    72  		return err
    73  	}
    74  
    75  	binary.LittleEndian.PutUint32(uint32Buf[:], sideRandomNumber)
    76  	if _, err := writer.Write(uint32Buf[:]); err != nil {
    77  		return err
    78  	}
    79  
    80  	binary.LittleEndian.PutUint32(uint32Buf[:], sideExtraNonce)
    81  	if _, err := writer.Write(uint32Buf[:]); err != nil {
    82  		return err
    83  	}
    84  
    85  	return nil
    86  }
    87  
    88  func (tpl *Template) Blob(preAllocatedBuffer []byte, nonce, extraNonce, sideRandomNumber, sideExtraNonce uint32, templateId types.Hash) []byte {
    89  	buf := append(preAllocatedBuffer, tpl.Buffer...)
    90  
    91  	// Overwrite nonce
    92  	binary.LittleEndian.PutUint32(buf[tpl.NonceOffset:], nonce)
    93  	// Overwrite extra nonce
    94  	binary.LittleEndian.PutUint32(buf[tpl.ExtraNonceOffset:], extraNonce)
    95  	// Overwrite template id
    96  	copy(buf[tpl.TemplateIdOffset:], templateId[:])
    97  	// Overwrite sidechain random number
    98  	binary.LittleEndian.PutUint32(buf[tpl.TemplateExtraBufferOffset+4*2:], sideRandomNumber)
    99  	// Overwrite sidechain extra nonce number
   100  	binary.LittleEndian.PutUint32(buf[tpl.TemplateExtraBufferOffset+4*3:], sideExtraNonce)
   101  
   102  	return buf
   103  }
   104  
   105  func (tpl *Template) TemplateId(hasher *sha3.HasherState, preAllocatedBuffer []byte, consensus *sidechain.Consensus, sideRandomNumber, sideExtraNonce uint32, result *types.Hash) {
   106  	buf := tpl.Blob(preAllocatedBuffer, 0, 0, sideRandomNumber, sideExtraNonce, types.ZeroHash)
   107  
   108  	_, _ = hasher.Write(buf)
   109  	_, _ = hasher.Write(consensus.Id[:])
   110  
   111  	crypto.HashFastSum(hasher, (*result)[:])
   112  	hasher.Reset()
   113  }
   114  
   115  func (tpl *Template) Timestamp() uint64 {
   116  	t, _ := binary.Uvarint(tpl.Buffer[2:])
   117  	return t
   118  }
   119  
   120  func (tpl *Template) ShareVersion(consensus *sidechain.Consensus) sidechain.ShareVersion {
   121  	return sidechain.P2PoolShareVersion(consensus, tpl.Timestamp())
   122  }
   123  
   124  func (tpl *Template) CoinbaseBufferLength() int {
   125  	return tpl.TransactionsOffset - tpl.CoinbaseOffset
   126  }
   127  
   128  func (tpl *Template) CoinbaseBlob(preAllocatedBuffer []byte, extraNonce uint32, templateId types.Hash) []byte {
   129  	buf := append(preAllocatedBuffer, tpl.Buffer[tpl.CoinbaseOffset:tpl.TransactionsOffset]...)
   130  
   131  	// Overwrite extra nonce
   132  	binary.LittleEndian.PutUint32(buf[tpl.ExtraNonceOffset-tpl.CoinbaseOffset:], extraNonce)
   133  	// Overwrite template id
   134  	copy(buf[tpl.TemplateIdOffset-tpl.CoinbaseOffset:], templateId[:])
   135  
   136  	return buf
   137  }
   138  
   139  func (tpl *Template) CoinbaseBlobId(hasher *sha3.HasherState, preAllocatedBuffer []byte, extraNonce uint32, templateId types.Hash, result *types.Hash) {
   140  
   141  	buf := tpl.CoinbaseBlob(preAllocatedBuffer, extraNonce, templateId)
   142  	_, _ = hasher.Write(buf[:len(buf)-1])
   143  	crypto.HashFastSum(hasher, (*result)[:])
   144  	hasher.Reset()
   145  
   146  	CoinbaseIdHash(hasher, *result, result)
   147  }
   148  
   149  func (tpl *Template) CoinbaseId(hasher *sha3.HasherState, extraNonce uint32, templateId types.Hash, result *types.Hash) {
   150  
   151  	var extraNonceBuf [4]byte
   152  
   153  	_, _ = hasher.Write(tpl.Buffer[tpl.CoinbaseOffset:tpl.ExtraNonceOffset])
   154  	// extra nonce
   155  	binary.LittleEndian.PutUint32(extraNonceBuf[:], extraNonce)
   156  	_, _ = hasher.Write(extraNonceBuf[:])
   157  
   158  	_, _ = hasher.Write(tpl.Buffer[tpl.ExtraNonceOffset+4 : tpl.TemplateIdOffset])
   159  	// template id
   160  	_, _ = hasher.Write(templateId[:])
   161  
   162  	_, _ = hasher.Write(tpl.Buffer[tpl.TemplateIdOffset+types.HashSize : tpl.TransactionsOffset-1])
   163  
   164  	crypto.HashFastSum(hasher, (*result)[:])
   165  	hasher.Reset()
   166  
   167  	CoinbaseIdHash(hasher, *result, result)
   168  }
   169  
   170  var zeroExtraBaseRCTHash = crypto.PooledKeccak256([]byte{0})
   171  
   172  func CoinbaseIdHash(hasher *sha3.HasherState, coinbaseBlobMinusBaseRTC types.Hash, result *types.Hash) {
   173  	_, _ = hasher.Write(coinbaseBlobMinusBaseRTC[:])
   174  	// Base RCT, single 0 byte in miner tx
   175  	_, _ = hasher.Write(zeroExtraBaseRCTHash[:])
   176  	// Prunable RCT, empty in miner tx
   177  	_, _ = hasher.Write(types.ZeroHash[:])
   178  	crypto.HashFastSum(hasher, (*result)[:])
   179  	hasher.Reset()
   180  }
   181  
   182  func (tpl *Template) HashingBlobBufferLength() int {
   183  	_, n := binary.Uvarint(tpl.Buffer[tpl.TransactionsOffset:])
   184  
   185  	return tpl.NonceOffset + 4 + types.HashSize + n
   186  }
   187  
   188  func (tpl *Template) HashingBlob(hasher *sha3.HasherState, preAllocatedBuffer []byte, nonce, extraNonce uint32, templateId types.Hash) []byte {
   189  
   190  	var rootHash types.Hash
   191  	tpl.CoinbaseId(hasher, extraNonce, templateId, &rootHash)
   192  
   193  	buf := append(preAllocatedBuffer, tpl.Buffer[:tpl.NonceOffset]...)
   194  	buf = binary.LittleEndian.AppendUint32(buf, nonce)
   195  
   196  	numTransactions, n := binary.Uvarint(tpl.Buffer[tpl.TransactionsOffset:])
   197  
   198  	if numTransactions < 1 {
   199  	} else if numTransactions < 2 {
   200  		_, _ = hasher.Write(rootHash[:])
   201  		_, _ = hasher.Write(tpl.Buffer[tpl.TransactionsOffset+n : tpl.TransactionsOffset+n+types.HashSize])
   202  		crypto.HashFastSum(hasher, rootHash[:])
   203  		hasher.Reset()
   204  	} else {
   205  		for i := range tpl.MerkleTreeMainBranch {
   206  			_, _ = hasher.Write(rootHash[:])
   207  			_, _ = hasher.Write(tpl.MerkleTreeMainBranch[i][:])
   208  			crypto.HashFastSum(hasher, rootHash[:])
   209  			hasher.Reset()
   210  		}
   211  	}
   212  
   213  	buf = append(buf, rootHash[:]...)
   214  	buf = binary.AppendUvarint(buf, numTransactions+1)
   215  	return buf
   216  }
   217  
   218  func TemplateFromPoolBlock(b *sidechain.PoolBlock) (tpl *Template, err error) {
   219  	if b.ShareVersion() < sidechain.ShareVersion_V1 || b.ShareVersion() > sidechain.ShareVersion_V2 {
   220  		return nil, errors.New("unsupported share version")
   221  	}
   222  	totalLen := b.BufferLength()
   223  	buf := make([]byte, 0, b.BufferLength())
   224  	if buf, err = b.AppendBinaryFlags(buf, false, false); err != nil {
   225  		return nil, err
   226  	}
   227  
   228  	tpl = &Template{
   229  		Buffer: buf,
   230  	}
   231  
   232  	mainBufferLength := b.Main.BufferLength()
   233  	coinbaseLength := b.Main.Coinbase.BufferLength()
   234  	tpl.NonceOffset = mainBufferLength - (4 + coinbaseLength + utils.UVarInt64Size(len(b.Main.Transactions)) + types.HashSize*len(b.Main.Transactions))
   235  
   236  	tpl.CoinbaseOffset = mainBufferLength - (coinbaseLength + utils.UVarInt64Size(len(b.Main.Transactions)) + types.HashSize*len(b.Main.Transactions))
   237  
   238  	tpl.TransactionsOffset = mainBufferLength - (utils.UVarInt64Size(len(b.Main.Transactions)) + types.HashSize*len(b.Main.Transactions))
   239  
   240  	tpl.ExtraNonceOffset = tpl.NonceOffset + 4 + (coinbaseLength - (b.Main.Coinbase.Extra[1].BufferLength() + b.Main.Coinbase.Extra[2].BufferLength() + 1)) + 1 + utils.UVarInt64Size(b.Main.Coinbase.Extra[1].VarInt)
   241  
   242  	tpl.TemplateIdOffset = tpl.NonceOffset + 4 + (coinbaseLength - (b.Main.Coinbase.Extra[2].BufferLength() + 1)) + 1 + utils.UVarInt64Size(b.Main.Coinbase.Extra[2].VarInt)
   243  	tpl.TemplateExtraBufferOffset = totalLen - 4*4
   244  
   245  	// Set places to zeroes where necessary
   246  	tpl.Buffer = tpl.Blob(make([]byte, 0, len(tpl.Buffer)), 0, 0, 0, 0, types.ZeroHash)
   247  
   248  	if len(b.Main.Transactions) > 1 {
   249  		merkleTree := make(crypto.BinaryTreeHash, len(b.Main.Transactions)+1)
   250  		copy(merkleTree[1:], b.Main.Transactions)
   251  		tpl.MerkleTreeMainBranch = merkleTree.MainBranch()
   252  	}
   253  
   254  	tpl.MainHeight = b.Main.Coinbase.GenHeight
   255  	tpl.MainParent = b.Main.PreviousId
   256  
   257  	tpl.SideHeight = b.Side.Height
   258  	tpl.SideParent = b.Side.Parent
   259  	tpl.SideDifficulty = b.Side.Difficulty
   260  
   261  	return tpl, nil
   262  }