Veronica 43b9523919
Adding support for mass. (#2301)
* Adding support for mass.

* update grpc v1.69.2

* Upgrade protos using latest protoc

* Use MassCommitment instead of Mass

* Fix DomainTransaction clone, equal and tests

---------

Co-authored-by: veronica <jimjouny@gmail.com>
Co-authored-by: Ori Newman <orinewman1@gmail.com>
2025-01-21 10:57:28 +02:00

370 lines
10 KiB
Go

package externalapi
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/pkg/errors"
)
// DomainTransaction represents a Kaspa transaction
type DomainTransaction struct {
Version uint16
Inputs []*DomainTransactionInput
Outputs []*DomainTransactionOutput
LockTime uint64
SubnetworkID DomainSubnetworkID
Gas uint64
Payload []byte
Fee uint64
Mass uint64
MassCommitment uint64
// ID is a field that is used to cache the transaction ID.
// Always use consensushashing.TransactionID instead of accessing this field directly
ID *DomainTransactionID
}
// Clone returns a clone of DomainTransaction
func (tx *DomainTransaction) Clone() *DomainTransaction {
payloadClone := make([]byte, len(tx.Payload))
copy(payloadClone, tx.Payload)
inputsClone := make([]*DomainTransactionInput, len(tx.Inputs))
for i, input := range tx.Inputs {
inputsClone[i] = input.Clone()
}
outputsClone := make([]*DomainTransactionOutput, len(tx.Outputs))
for i, output := range tx.Outputs {
outputsClone[i] = output.Clone()
}
var idClone *DomainTransactionID
if tx.ID != nil {
idClone = tx.ID.Clone()
}
return &DomainTransaction{
Version: tx.Version,
Inputs: inputsClone,
Outputs: outputsClone,
LockTime: tx.LockTime,
SubnetworkID: *tx.SubnetworkID.Clone(),
Gas: tx.Gas,
Payload: payloadClone,
Fee: tx.Fee,
Mass: tx.Mass,
MassCommitment: tx.MassCommitment,
ID: idClone,
}
}
// If this doesn't compile, it means the type definition has been changed, so it's
// an indication to update Equal and Clone accordingly.
var _ = DomainTransaction{0, []*DomainTransactionInput{}, []*DomainTransactionOutput{}, 0,
DomainSubnetworkID{}, 0, []byte{}, 0, 0, 0,
&DomainTransactionID{}}
// Equal returns whether tx equals to other
func (tx *DomainTransaction) Equal(other *DomainTransaction) bool {
if tx == nil || other == nil {
return tx == other
}
if tx.Version != other.Version {
return false
}
if len(tx.Inputs) != len(other.Inputs) {
return false
}
for i, input := range tx.Inputs {
if !input.Equal(other.Inputs[i]) {
return false
}
}
if len(tx.Outputs) != len(other.Outputs) {
return false
}
for i, output := range tx.Outputs {
if !output.Equal(other.Outputs[i]) {
return false
}
}
if tx.LockTime != other.LockTime {
return false
}
if !tx.SubnetworkID.Equal(&other.SubnetworkID) {
return false
}
if tx.Gas != other.Gas {
return false
}
if !bytes.Equal(tx.Payload, other.Payload) {
return false
}
if tx.MassCommitment != other.MassCommitment {
return false
}
if tx.Fee != 0 && other.Fee != 0 && tx.Fee != other.Fee {
panic(errors.New("identical transactions should always have the same fee"))
}
if tx.Mass != 0 && other.Mass != 0 && tx.Mass != other.Mass {
panic(errors.New("identical transactions should always have the same mass"))
}
if tx.ID != nil && other.ID != nil && !tx.ID.Equal(other.ID) {
panic(errors.New("identical transactions should always have the same ID"))
}
return true
}
// DomainTransactionInput represents a Kaspa transaction input
type DomainTransactionInput struct {
PreviousOutpoint DomainOutpoint
SignatureScript []byte
Sequence uint64
SigOpCount byte
UTXOEntry UTXOEntry
}
// If this doesn't compile, it means the type definition has been changed, so it's
// an indication to update Equal and Clone accordingly.
var _ = &DomainTransactionInput{DomainOutpoint{}, []byte{}, 0, 0, nil}
// Equal returns whether input equals to other
func (input *DomainTransactionInput) Equal(other *DomainTransactionInput) bool {
if input == nil || other == nil {
return input == other
}
if !input.PreviousOutpoint.Equal(&other.PreviousOutpoint) {
return false
}
if !bytes.Equal(input.SignatureScript, other.SignatureScript) {
return false
}
if input.Sequence != other.Sequence {
return false
}
if input.SigOpCount != other.SigOpCount {
return false
}
if input.UTXOEntry != nil && other.UTXOEntry != nil && !input.UTXOEntry.Equal(other.UTXOEntry) {
panic(errors.New("identical inputs should always have the same UTXO entry"))
}
return true
}
// Clone returns a clone of DomainTransactionInput
func (input *DomainTransactionInput) Clone() *DomainTransactionInput {
signatureScriptClone := make([]byte, len(input.SignatureScript))
copy(signatureScriptClone, input.SignatureScript)
return &DomainTransactionInput{
PreviousOutpoint: *input.PreviousOutpoint.Clone(),
SignatureScript: signatureScriptClone,
Sequence: input.Sequence,
SigOpCount: input.SigOpCount,
UTXOEntry: input.UTXOEntry,
}
}
// DomainOutpoint represents a Kaspa transaction outpoint
type DomainOutpoint struct {
TransactionID DomainTransactionID
Index uint32
}
// If this doesn't compile, it means the type definition has been changed, so it's
// an indication to update Equal and Clone accordingly.
var _ = DomainOutpoint{DomainTransactionID{}, 0}
// Equal returns whether op equals to other
func (op *DomainOutpoint) Equal(other *DomainOutpoint) bool {
if op == nil || other == nil {
return op == other
}
return *op == *other
}
// Clone returns a clone of DomainOutpoint
func (op *DomainOutpoint) Clone() *DomainOutpoint {
return &DomainOutpoint{
TransactionID: *op.TransactionID.Clone(),
Index: op.Index,
}
}
// String stringifies an outpoint.
func (op DomainOutpoint) String() string {
return fmt.Sprintf("(%s: %d)", op.TransactionID, op.Index)
}
// NewDomainOutpoint instantiates a new DomainOutpoint with the given id and index
func NewDomainOutpoint(id *DomainTransactionID, index uint32) *DomainOutpoint {
return &DomainOutpoint{
TransactionID: *id,
Index: index,
}
}
// ScriptPublicKey represents a Kaspad ScriptPublicKey
type ScriptPublicKey struct {
Script []byte
Version uint16
}
// Equal returns whether spk equals to other
func (spk *ScriptPublicKey) Equal(other *ScriptPublicKey) bool {
if spk == nil || other == nil {
return spk == other
}
if spk.Version != other.Version {
return false
}
return bytes.Equal(spk.Script, other.Script)
}
// String stringifies a ScriptPublicKey.
func (spk *ScriptPublicKey) String() string {
var versionBytes = make([]byte, 2) // uint16
binary.LittleEndian.PutUint16(versionBytes, spk.Version)
versionString := string(versionBytes)
scriptString := string(spk.Script)
return versionString + scriptString
}
// NewScriptPublicKeyFromString converts the given string to a scriptPublicKey
func NewScriptPublicKeyFromString(ScriptPublicKeyString string) *ScriptPublicKey {
bytes := []byte(ScriptPublicKeyString)
version := binary.LittleEndian.Uint16(bytes[:2])
script := bytes[2:]
return &ScriptPublicKey{Script: script, Version: version}
}
// DomainTransactionOutput represents a Kaspad transaction output
type DomainTransactionOutput struct {
Value uint64
ScriptPublicKey *ScriptPublicKey
}
// If this doesn't compile, it means the type definition has been changed, so it's
// an indication to update Equal and Clone accordingly.
var _ = DomainTransactionOutput{0, &ScriptPublicKey{Script: []byte{}, Version: 0}}
// Equal returns whether output equals to other
func (output *DomainTransactionOutput) Equal(other *DomainTransactionOutput) bool {
if output == nil || other == nil {
return output == other
}
if output.Value != other.Value {
return false
}
return output.ScriptPublicKey.Equal(other.ScriptPublicKey)
}
// Clone returns a clone of DomainTransactionOutput
func (output *DomainTransactionOutput) Clone() *DomainTransactionOutput {
scriptPublicKeyClone := &ScriptPublicKey{
Script: make([]byte, len(output.ScriptPublicKey.Script)),
Version: output.ScriptPublicKey.Version}
copy(scriptPublicKeyClone.Script, output.ScriptPublicKey.Script)
return &DomainTransactionOutput{
Value: output.Value,
ScriptPublicKey: scriptPublicKeyClone,
}
}
// DomainTransactionID represents the ID of a Kaspa transaction
type DomainTransactionID DomainHash
// NewDomainTransactionIDFromByteArray constructs a new TransactionID out of a byte array
func NewDomainTransactionIDFromByteArray(transactionIDBytes *[DomainHashSize]byte) *DomainTransactionID {
return (*DomainTransactionID)(NewDomainHashFromByteArray(transactionIDBytes))
}
// NewDomainTransactionIDFromByteSlice constructs a new TransactionID out of a byte slice
// Returns an error if the length of the byte slice is not exactly `DomainHashSize`
func NewDomainTransactionIDFromByteSlice(transactionIDBytes []byte) (*DomainTransactionID, error) {
hash, err := NewDomainHashFromByteSlice(transactionIDBytes)
if err != nil {
return nil, err
}
return (*DomainTransactionID)(hash), nil
}
// NewDomainTransactionIDFromString constructs a new TransactionID out of a string
// Returns an error if the length of the string is not exactly `DomainHashSize * 2`
func NewDomainTransactionIDFromString(transactionIDString string) (*DomainTransactionID, error) {
hash, err := NewDomainHashFromString(transactionIDString)
if err != nil {
return nil, err
}
return (*DomainTransactionID)(hash), nil
}
// String stringifies a transaction ID.
func (id DomainTransactionID) String() string {
return DomainHash(id).String()
}
// Clone returns a clone of DomainTransactionID
func (id *DomainTransactionID) Clone() *DomainTransactionID {
idClone := *id
return &idClone
}
// Equal returns whether id equals to other
func (id *DomainTransactionID) Equal(other *DomainTransactionID) bool {
return (*DomainHash)(id).Equal((*DomainHash)(other))
}
// Less returns true if id is less than other
func (id *DomainTransactionID) Less(other *DomainTransactionID) bool {
return (*DomainHash)(id).Less((*DomainHash)(other))
}
// LessOrEqual returns true if id is smaller or equal to other
func (id *DomainTransactionID) LessOrEqual(other *DomainTransactionID) bool {
return (*DomainHash)(id).LessOrEqual((*DomainHash)(other))
}
// ByteArray returns the bytes in this transactionID represented as a byte array.
// The transactionID bytes are cloned, therefore it is safe to modify the resulting array.
func (id *DomainTransactionID) ByteArray() *[DomainHashSize]byte {
return (*DomainHash)(id).ByteArray()
}
// ByteSlice returns the bytes in this transactionID represented as a byte slice.
// The transactionID bytes are cloned, therefore it is safe to modify the resulting slice.
func (id *DomainTransactionID) ByteSlice() []byte {
return (*DomainHash)(id).ByteSlice()
}