mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-05-19 13:26:47 +00:00

* Move CalculateSignatureHash to consensushashing * Added CalcSignatureHash_BIP143 with all parameters except the re-used hashes * Add handling of outputHash * Add sequencesHash to the mix * Add previousOutputsHash to the mix * Replace legacy CalculateSigHash with new one, and re-wire to all non-test code * Add missing types to WriteElement * Fix tests in txscript * Fix tests in rest of code * Add missing comments * Add SubnetworkID and Gas to sigHash * Add TestCalculateSignatureHash * Invert condition in SigHashSingle getOutputsHash * Explicitly define that payloadHash for native transactions is 0 * added benchmark to CalculateSignatureHash * Reformat call for signAndCheck * Change SigHashes to be true bit-fields * Add check for transaction version * Write length of byte array in WriteElement * hashOutpoint should get outpoint, not txIn * Use inputIndex instead of i to determine SigHashType * Use correct transaction version + fix some typos * Fix hashes in test * Reformat an overly-long line * Replace checkHashTypeEncoding with caalls to hashType.IsStandardSigHashType * Convert hashType to uint8 * Add comment
237 lines
4.7 KiB
Go
237 lines
4.7 KiB
Go
package serialization
|
|
|
|
import (
|
|
"io"
|
|
|
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
"github.com/kaspanet/kaspad/util/binaryserializer"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// errNoEncodingForType signifies that there's no encoding for the given type.
|
|
var errNoEncodingForType = errors.New("there's no encoding for this type")
|
|
|
|
var errMalformed = errors.New("errMalformed")
|
|
|
|
// WriteElement writes the little endian representation of element to w.
|
|
func WriteElement(w io.Writer, element interface{}) error {
|
|
// Attempt to write the element based on the concrete type via fast
|
|
// type assertions first.
|
|
switch e := element.(type) {
|
|
case []byte:
|
|
err := WriteElement(w, uint64(len(e)))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = w.Write(e)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
case int16:
|
|
err := binaryserializer.PutUint16(w, uint16(e))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
case uint16:
|
|
err := binaryserializer.PutUint16(w, e)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
case int32:
|
|
err := binaryserializer.PutUint32(w, uint32(e))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
|
|
case uint32:
|
|
err := binaryserializer.PutUint32(w, e)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
|
|
case int64:
|
|
err := binaryserializer.PutUint64(w, uint64(e))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
|
|
case uint64:
|
|
err := binaryserializer.PutUint64(w, e)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
|
|
case uint8:
|
|
err := binaryserializer.PutUint8(w, e)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
|
|
case bool:
|
|
var err error
|
|
if e {
|
|
err = binaryserializer.PutUint8(w, 0x01)
|
|
} else {
|
|
err = binaryserializer.PutUint8(w, 0x00)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
|
|
case externalapi.DomainHash:
|
|
_, err := w.Write(e.ByteSlice())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
|
|
case *externalapi.DomainHash:
|
|
_, err := w.Write(e.ByteSlice())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
|
|
case externalapi.DomainTransactionID:
|
|
_, err := w.Write(e.ByteSlice())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
|
|
case externalapi.DomainSubnetworkID:
|
|
_, err := w.Write(e[:])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
|
|
case *externalapi.DomainSubnetworkID:
|
|
_, err := w.Write(e[:])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
return errors.Wrapf(errNoEncodingForType, "couldn't find a way to write type %T", element)
|
|
}
|
|
|
|
// WriteElements writes multiple items to w. It is equivalent to multiple
|
|
// calls to writeElement.
|
|
func WriteElements(w io.Writer, elements ...interface{}) error {
|
|
for _, element := range elements {
|
|
err := WriteElement(w, element)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ReadElement reads the next sequence of bytes from r using little endian
|
|
// depending on the concrete type of element pointed to.
|
|
func ReadElement(r io.Reader, element interface{}) error {
|
|
// Attempt to read the element based on the concrete type via fast
|
|
// type assertions first.
|
|
switch e := element.(type) {
|
|
case *int16:
|
|
rv, err := binaryserializer.Uint16(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e = int16(rv)
|
|
return nil
|
|
|
|
case *uint16:
|
|
rv, err := binaryserializer.Uint16(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e = rv
|
|
return nil
|
|
case *int32:
|
|
rv, err := binaryserializer.Uint32(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e = int32(rv)
|
|
return nil
|
|
|
|
case *uint32:
|
|
rv, err := binaryserializer.Uint32(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e = rv
|
|
return nil
|
|
|
|
case *int64:
|
|
rv, err := binaryserializer.Uint64(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e = int64(rv)
|
|
return nil
|
|
|
|
case *uint64:
|
|
rv, err := binaryserializer.Uint64(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e = rv
|
|
return nil
|
|
|
|
case *uint8:
|
|
rv, err := binaryserializer.Uint8(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*e = rv
|
|
return nil
|
|
|
|
case *bool:
|
|
rv, err := binaryserializer.Uint8(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if rv == 0x00 {
|
|
*e = false
|
|
} else if rv == 0x01 {
|
|
*e = true
|
|
} else {
|
|
return errors.Wrapf(errMalformed, "in order to keep serialization canonical, true has to"+
|
|
" always be 0x01")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
return errors.Wrapf(errNoEncodingForType, "couldn't find a way to read type %T", element)
|
|
}
|
|
|
|
// ReadElements reads multiple items from r. It is equivalent to multiple
|
|
// calls to ReadElement.
|
|
func ReadElements(r io.Reader, elements ...interface{}) error {
|
|
for _, element := range elements {
|
|
err := ReadElement(r, element)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// IsMalformedError returns whether the error indicates a malformed data source
|
|
func IsMalformedError(err error) bool {
|
|
return errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) || errors.Is(err, errMalformed)
|
|
}
|