ceremonyclient/node/execution/intrinsics/token/token_conversions.go
Cassandra Heart 53f7c2b5c9
v2.1.0.2 (#442)
* v2.1.0.2

* restore tweaks to simlibp2p

* fix: nil ref on size calc

* fix: panic should induce shutdown from event_distributor

* fix: friendlier initialization that requires less manual kickstarting for test/devnets

* fix: fewer available shards than provers should choose shard length

* fix: update stored worker registry, improve logging for debug mode

* fix: shut the fuck up, peer log

* qol: log value should be snake cased

* fix:non-archive snap sync issues

* fix: separate X448/Decaf448 signed keys, add onion key to registry

* fix: overflow arithmetic on frame number comparison

* fix: worker registration should be idempotent if inputs are same, otherwise permit updated records

* fix: remove global prover state from size calculation

* fix: divide by zero case

* fix: eager prover

* fix: broadcast listener default

* qol: diagnostic data for peer authenticator

* fix: master/worker connectivity issue in sparse networks

tight coupling of peer and workers can sometimes interfere if mesh is sparse, so give workers a pseudoidentity but publish messages with the proper peer key

* fix: reorder steps of join creation

* fix: join verify frame source + ensure domain is properly padded (unnecessary but good for consistency)

* fix: add delegate to protobuf <-> reified join conversion

* fix: preempt prover from planning with no workers

* fix: use the unallocated workers to generate a proof

* qol: underflow causes join fail in first ten frames on test/devnets

* qol: small logging tweaks for easier log correlation in debug mode

* qol: use fisher-yates shuffle to ensure prover allocations are evenly distributed when scores are equal

* qol: separate decisional logic on post-enrollment confirmation into consensus engine, proposer, and worker manager where relevant, refactor out scoring

* reuse shard descriptors for both join planning and confirm/reject decisions

* fix: add missing interface method and amend test blossomsub to use new peer id basis

* fix: only check allocations if they exist

* fix: pomw mint proof data needs to be hierarchically under global intrinsic domain

* staging temporary state under diagnostics

* fix: first phase of distributed lock refactoring

* fix: compute intrinsic locking

* fix: hypergraph intrinsic locking

* fix: token intrinsic locking

* fix: update execution engines to support new locking model

* fix: adjust tests with new execution shape

* fix: weave in lock/unlock semantics to liveness provider

* fix lock fallthrough, add missing allocation update

* qol: additional logging for diagnostics, also testnet/devnet handling for confirmations

* fix: establish grace period on halt scenario to permit recovery

* fix: support test/devnet defaults for coverage scenarios

* fix: nil ref on consensus halts for non-archive nodes

* fix: remove unnecessary prefix from prover ref

* add test coverage for fork choice behaviors and replay – once passing, blocker (2) is resolved

* fix: no fork replay on repeat for non-archive nodes, snap now behaves correctly

* rollup of pre-liveness check lock interactions

* ahead of tests, get the protobuf/metrics-related changes out so teams can prepare

* add test coverage for distributed lock behaviors – once passing, blocker (3) is resolved

* fix: blocker (3)

* Dev docs improvements (#445)

* Make install deps script more robust

* Improve testing instructions

* Worker node should stop upon OS SIGINT/SIGTERM signal (#447)

* move pebble close to Stop()

* move deferred Stop() to Start()

* add core id to worker stop log message

* create done os signal channel and stop worker upon message to it

---------

Co-authored-by: Cassandra Heart <7929478+CassOnMars@users.noreply.github.com>

---------

Co-authored-by: Daz <daz_the_corgi@proton.me>
Co-authored-by: Black Swan <3999712+blacks1ne@users.noreply.github.com>
2025-10-23 01:03:06 -05:00

936 lines
23 KiB
Go

package token
import (
"math/big"
"github.com/pkg/errors"
"source.quilibrium.com/quilibrium/monorepo/protobufs"
"source.quilibrium.com/quilibrium/monorepo/types/crypto"
"source.quilibrium.com/quilibrium/monorepo/types/tries"
)
// FromProtobuf converts a protobuf Authority to intrinsics Authority
func AuthorityFromProtobuf(pb *protobufs.Authority) (*Authority, error) {
if pb == nil {
return nil, nil
}
return &Authority{
KeyType: crypto.KeyType(pb.KeyType),
PublicKey: pb.PublicKey,
CanBurn: pb.CanBurn,
}, nil
}
// ToProtobuf converts an intrinsics Authority to protobuf Authority
func (a *Authority) ToProtobuf() *protobufs.Authority {
if a == nil {
return nil
}
return &protobufs.Authority{
KeyType: uint32(a.KeyType),
PublicKey: a.PublicKey,
CanBurn: a.CanBurn,
}
}
// FromProtobuf converts a protobuf FeeBasis to intrinsics FeeBasis
func FeeBasisFromProtobuf(pb *protobufs.FeeBasis) (*FeeBasis, error) {
if pb == nil {
return nil, nil
}
baseline := new(big.Int)
if len(pb.Baseline) > 0 {
baseline.SetBytes(pb.Baseline)
}
return &FeeBasis{
Type: FeeBasisType(pb.Type),
Baseline: baseline,
}, nil
}
// ToProtobuf converts an intrinsics FeeBasis to protobuf FeeBasis
func (f *FeeBasis) ToProtobuf() *protobufs.FeeBasis {
if f == nil {
return nil
}
var baseline []byte
if f.Baseline != nil {
baseline = f.Baseline.Bytes()
}
return &protobufs.FeeBasis{
Type: protobufs.FeeBasisType(f.Type),
Baseline: baseline,
}
}
// FromProtobuf converts a protobuf TokenMintStrategy to intrinsics
// TokenMintStrategy
func TokenMintStrategyFromProtobuf(pb *protobufs.TokenMintStrategy) (
*TokenMintStrategy,
error,
) {
if pb == nil {
return nil, nil
}
authority, err := AuthorityFromProtobuf(pb.Authority)
if err != nil {
return nil, errors.Wrap(err, "converting authority")
}
feeBasis, err := FeeBasisFromProtobuf(pb.FeeBasis)
if err != nil {
return nil, errors.Wrap(err, "converting fee basis")
}
return &TokenMintStrategy{
MintBehavior: TokenMintBehavior(pb.MintBehavior),
ProofBasis: ProofBasisType(pb.ProofBasis),
VerkleRoot: pb.VerkleRoot,
Authority: authority,
PaymentAddress: pb.PaymentAddress,
FeeBasis: feeBasis,
}, nil
}
// ToProtobuf converts an intrinsics TokenMintStrategy to protobuf
// TokenMintStrategy
func (t *TokenMintStrategy) ToProtobuf() *protobufs.TokenMintStrategy {
if t == nil {
return nil
}
return &protobufs.TokenMintStrategy{
MintBehavior: protobufs.TokenMintBehavior(t.MintBehavior),
ProofBasis: protobufs.ProofBasisType(t.ProofBasis),
VerkleRoot: t.VerkleRoot,
Authority: t.Authority.ToProtobuf(),
PaymentAddress: t.PaymentAddress,
FeeBasis: t.FeeBasis.ToProtobuf(),
}
}
// FromProtobuf converts a protobuf TokenDeploy to intrinsics TokenDeploy
func TokenDeployFromProtobuf(
pb *protobufs.TokenDeploy,
) (*TokenDeploy, error) {
if pb == nil {
return nil, nil
}
config, err := TokenConfigurationFromProtobuf(pb.Config)
if err != nil {
return nil, errors.Wrap(err, "token deploy from protobuf")
}
return &TokenDeploy{
Config: config,
RDFSchema: pb.RdfSchema,
}, nil
}
// ToProtobuf converts an intrinsics TokenDeploy to protobuf TokenDeploy
func (
t *TokenDeploy,
) ToProtobuf() *protobufs.TokenDeploy {
if t == nil {
return nil
}
return &protobufs.TokenDeploy{
Config: t.Config.ToProtobuf(),
RdfSchema: t.RDFSchema,
}
}
// FromProtobuf converts a protobuf TokenUpdate to intrinsics TokenUpdate
func TokenUpdateFromProtobuf(
pb *protobufs.TokenUpdate,
) (*TokenUpdate, error) {
if pb == nil {
return nil, nil
}
config, err := TokenConfigurationFromProtobuf(pb.Config)
if err != nil {
return nil, errors.Wrap(err, "token update from protobuf")
}
return &TokenUpdate{
Config: config,
RDFSchema: pb.RdfSchema,
OwnerSignature: pb.PublicKeySignatureBls48581,
}, nil
}
// ToProtobuf converts an intrinsics TokenUpdate to protobuf TokenUpdate
func (
t *TokenUpdate,
) ToProtobuf() *protobufs.TokenUpdate {
if t == nil {
return nil
}
return &protobufs.TokenUpdate{
Config: t.Config.ToProtobuf(),
RdfSchema: t.RDFSchema,
PublicKeySignatureBls48581: t.OwnerSignature,
}
}
// FromProtobuf converts a protobuf TokenConfiguration to intrinsics
// TokenIntrinsicConfiguration
func TokenConfigurationFromProtobuf(pb *protobufs.TokenConfiguration) (
*TokenIntrinsicConfiguration,
error,
) {
if pb == nil {
return nil, nil
}
mintStrategy, err := TokenMintStrategyFromProtobuf(pb.MintStrategy)
if err != nil {
return nil, errors.Wrap(err, "converting mint strategy")
}
var units *big.Int
if len(pb.Units) > 0 {
units = new(big.Int).SetBytes(pb.Units)
}
var supply *big.Int
if len(pb.Supply) > 0 {
supply = new(big.Int).SetBytes(pb.Supply)
}
// Convert AdditionalReference from [][]byte to [64]byte
var additionalRef [64]byte
if len(pb.AdditionalReference) > 0 && len(pb.AdditionalReference[0]) > 0 {
copy(additionalRef[:], pb.AdditionalReference[0])
}
return &TokenIntrinsicConfiguration{
Behavior: TokenIntrinsicBehavior(pb.Behavior),
MintStrategy: mintStrategy,
Units: units,
Supply: supply,
Name: pb.Name,
Symbol: pb.Symbol,
AdditionalReference: additionalRef,
}, nil
}
// ToProtobuf converts an intrinsics TokenIntrinsicConfiguration to protobuf
// TokenConfiguration
func (
t *TokenIntrinsicConfiguration,
) ToProtobuf() *protobufs.TokenConfiguration {
if t == nil {
return nil
}
var units []byte
if t.Units != nil {
units = t.Units.Bytes()
}
var supply []byte
if t.Supply != nil {
supply = t.Supply.Bytes()
}
return &protobufs.TokenConfiguration{
Behavior: uint32(t.Behavior),
MintStrategy: t.MintStrategy.ToProtobuf(),
Units: units,
Supply: supply,
Name: t.Name,
Symbol: t.Symbol,
AdditionalReference: [][]byte{t.AdditionalReference[:]},
}
}
// FromProtobuf converts a protobuf RecipientBundle to intrinsics
// RecipientBundle
func RecipientBundleFromProtobuf(pb *protobufs.RecipientBundle) (
*RecipientBundle,
error,
) {
if pb == nil {
return nil, nil
}
// Validate field lengths
if len(pb.OneTimeKey) != 56 {
return nil, errors.Errorf(
"invalid OneTimeKey length: expected 56, got %d",
len(pb.OneTimeKey),
)
}
if len(pb.VerificationKey) != 56 {
return nil, errors.Errorf(
"invalid VerificationKey length: expected 56, got %d",
len(pb.VerificationKey),
)
}
if len(pb.CoinBalance) != 56 {
return nil, errors.Errorf(
"invalid CoinBalance length: expected 56, got %d",
len(pb.CoinBalance),
)
}
if len(pb.Mask) != 56 {
return nil, errors.Errorf(
"invalid Mask length: expected 56, got %d",
len(pb.Mask),
)
}
if len(pb.AdditionalReference) != 0 && len(pb.AdditionalReference) != 64 {
return nil, errors.Errorf(
"invalid AdditionalReference length: expected 0 or 64, got %d",
len(pb.AdditionalReference),
)
}
if len(pb.AdditionalReferenceKey) != 0 && len(pb.AdditionalReferenceKey) != 56 {
return nil, errors.Errorf(
"invalid AdditionalReferenceKey length: expected 0 or 56, got %d",
len(pb.AdditionalReferenceKey),
)
}
return &RecipientBundle{
OneTimeKey: pb.OneTimeKey,
VerificationKey: pb.VerificationKey,
CoinBalance: pb.CoinBalance,
Mask: pb.Mask,
AdditionalReference: pb.AdditionalReference,
AdditionalReferenceKey: pb.AdditionalReferenceKey,
}, nil
}
// ToProtobuf converts an intrinsics RecipientBundle to protobuf RecipientBundle
func (r *RecipientBundle) ToProtobuf() *protobufs.RecipientBundle {
if r == nil {
return nil
}
return &protobufs.RecipientBundle{
OneTimeKey: r.OneTimeKey,
VerificationKey: r.VerificationKey,
CoinBalance: r.CoinBalance,
Mask: r.Mask,
AdditionalReference: r.AdditionalReference,
AdditionalReferenceKey: r.AdditionalReferenceKey,
}
}
// FromProtobuf converts a protobuf TransactionInput to intrinsics
// TransactionInput
func TransactionInputFromProtobuf(pb *protobufs.TransactionInput) (
*TransactionInput,
error,
) {
if pb == nil {
return nil, nil
}
return &TransactionInput{
Commitment: pb.Commitment,
Signature: pb.Signature,
Proofs: pb.Proofs,
}, nil
}
// ToProtobuf converts an intrinsics TransactionInput to protobuf
// TransactionInput
func (t *TransactionInput) ToProtobuf() *protobufs.TransactionInput {
if t == nil {
return nil
}
return &protobufs.TransactionInput{
Commitment: t.Commitment,
Signature: t.Signature,
Proofs: t.Proofs,
}
}
// FromProtobuf converts a protobuf TransactionOutput to intrinsics
// TransactionOutput
func TransactionOutputFromProtobuf(pb *protobufs.TransactionOutput) (
*TransactionOutput,
error,
) {
if pb == nil {
return nil, nil
}
recipientOutput, err := RecipientBundleFromProtobuf(pb.RecipientOutput)
if err != nil {
return nil, errors.Wrap(err, "converting recipient output")
}
return &TransactionOutput{
FrameNumber: pb.FrameNumber,
Commitment: pb.Commitment,
RecipientOutput: *recipientOutput,
}, nil
}
// ToProtobuf converts an intrinsics TransactionOutput to protobuf
// TransactionOutput
func (t *TransactionOutput) ToProtobuf() *protobufs.TransactionOutput {
if t == nil {
return nil
}
return &protobufs.TransactionOutput{
FrameNumber: t.FrameNumber,
Commitment: t.Commitment,
RecipientOutput: t.RecipientOutput.ToProtobuf(),
}
}
// FromProtobuf converts a protobuf Transaction to intrinsics Transaction
func TransactionFromProtobuf(
pb *protobufs.Transaction,
inclusionProver crypto.InclusionProver,
) (*Transaction, error) {
if pb == nil {
return nil, nil
}
// Convert domain from slice to array
var domain [32]byte
copy(domain[:], pb.Domain)
// Convert inputs
inputs := make([]*TransactionInput, len(pb.Inputs))
for i, input := range pb.Inputs {
converted, err := TransactionInputFromProtobuf(input)
if err != nil {
return nil, errors.Wrapf(err, "converting input %d", i)
}
inputs[i] = converted
}
// Convert outputs
outputs := make([]*TransactionOutput, len(pb.Outputs))
for i, output := range pb.Outputs {
converted, err := TransactionOutputFromProtobuf(output)
if err != nil {
return nil, errors.Wrapf(err, "converting output %d", i)
}
outputs[i] = converted
}
// Convert fees from [][]byte to []*big.Int
fees := make([]*big.Int, len(pb.Fees))
for i, fee := range pb.Fees {
fees[i] = new(big.Int).SetBytes(fee)
}
proof, err := TraversalProofFromProtobuf(pb.TraversalProof, inclusionProver)
if err != nil {
return nil, err
}
return &Transaction{
Domain: domain,
Inputs: inputs,
Outputs: outputs,
Fees: fees,
RangeProof: pb.RangeProof,
TraversalProof: proof,
// Runtime dependencies will be injected separately
}, nil
}
// ToProtobuf converts an intrinsics Transaction to protobuf Transaction
func (t *Transaction) ToProtobuf() *protobufs.Transaction {
if t == nil {
return nil
}
// Convert inputs
inputs := make([]*protobufs.TransactionInput, len(t.Inputs))
for i, input := range t.Inputs {
inputs[i] = input.ToProtobuf()
}
// Convert outputs
outputs := make([]*protobufs.TransactionOutput, len(t.Outputs))
for i, output := range t.Outputs {
outputs[i] = output.ToProtobuf()
}
// Convert fees from []*big.Int to [][]byte
fees := make([][]byte, len(t.Fees))
for i, fee := range t.Fees {
if fee != nil {
fees[i] = fee.Bytes()
}
}
// Convert TraversalProof if present
var traversalProof *protobufs.TraversalProof
if t.TraversalProof != nil {
// Convert qcrypto.TraversalProof to protobufs.TraversalProof
traversalProof = TraversalProofToProtobuf(t.TraversalProof)
}
return &protobufs.Transaction{
Domain: t.Domain[:],
Inputs: inputs,
Outputs: outputs,
Fees: fees,
RangeProof: t.RangeProof,
TraversalProof: traversalProof,
}
}
// FromProtobuf converts a protobuf PendingTransactionInput to intrinsics
// PendingTransactionInput
func PendingTransactionInputFromProtobuf(
pb *protobufs.PendingTransactionInput,
) (*PendingTransactionInput, error) {
if pb == nil {
return nil, nil
}
return &PendingTransactionInput{
Commitment: pb.Commitment,
Signature: pb.Signature,
Proofs: pb.Proofs,
}, nil
}
// ToProtobuf converts an intrinsics PendingTransactionInput to protobuf
// PendingTransactionInput
func (
p *PendingTransactionInput,
) ToProtobuf() *protobufs.PendingTransactionInput {
if p == nil {
return nil
}
return &protobufs.PendingTransactionInput{
Commitment: p.Commitment,
Signature: p.Signature,
Proofs: p.Proofs,
}
}
// FromProtobuf converts a protobuf PendingTransactionOutput to intrinsics
// PendingTransactionOutput
func PendingTransactionOutputFromProtobuf(
pb *protobufs.PendingTransactionOutput,
) (*PendingTransactionOutput, error) {
if pb == nil {
return nil, nil
}
toOutput, err := RecipientBundleFromProtobuf(pb.To)
if err != nil {
return nil, errors.Wrap(err, "converting to output")
}
refundOutput, err := RecipientBundleFromProtobuf(pb.Refund)
if err != nil {
return nil, errors.Wrap(err, "converting refund output")
}
return &PendingTransactionOutput{
FrameNumber: pb.FrameNumber,
Commitment: pb.Commitment,
ToOutput: *toOutput,
RefundOutput: *refundOutput,
Expiration: pb.Expiration,
}, nil
}
// ToProtobuf converts an intrinsics PendingTransactionOutput to protobuf
// PendingTransactionOutput
func (
p *PendingTransactionOutput,
) ToProtobuf() *protobufs.PendingTransactionOutput {
if p == nil {
return nil
}
return &protobufs.PendingTransactionOutput{
FrameNumber: p.FrameNumber,
Commitment: p.Commitment,
To: p.ToOutput.ToProtobuf(),
Refund: p.RefundOutput.ToProtobuf(),
Expiration: p.Expiration,
}
}
// FromProtobuf converts a protobuf PendingTransaction to intrinsics
// PendingTransaction
func PendingTransactionFromProtobuf(
pb *protobufs.PendingTransaction,
inclusionProver crypto.InclusionProver,
) (
*PendingTransaction,
error,
) {
if pb == nil {
return nil, nil
}
// Convert domain from slice to array
var domain [32]byte
copy(domain[:], pb.Domain)
// Convert inputs
inputs := make([]*PendingTransactionInput, len(pb.Inputs))
for i, input := range pb.Inputs {
converted, err := PendingTransactionInputFromProtobuf(input)
if err != nil {
return nil, errors.Wrapf(err, "converting input %d", i)
}
inputs[i] = converted
}
// Convert outputs
outputs := make([]*PendingTransactionOutput, len(pb.Outputs))
for i, output := range pb.Outputs {
converted, err := PendingTransactionOutputFromProtobuf(output)
if err != nil {
return nil, errors.Wrapf(err, "converting output %d", i)
}
outputs[i] = converted
}
// Convert fees from [][]byte to []*big.Int
fees := make([]*big.Int, len(pb.Fees))
for i, fee := range pb.Fees {
fees[i] = new(big.Int).SetBytes(fee)
}
proof, err := TraversalProofFromProtobuf(pb.TraversalProof, inclusionProver)
if err != nil {
return nil, err
}
return &PendingTransaction{
Domain: domain,
Inputs: inputs,
Outputs: outputs,
Fees: fees,
RangeProof: pb.RangeProof,
TraversalProof: proof,
// Runtime dependencies will be injected separately
}, nil
}
// ToProtobuf converts an intrinsics PendingTransaction to protobuf
// PendingTransaction
func (p *PendingTransaction) ToProtobuf() *protobufs.PendingTransaction {
if p == nil {
return nil
}
// Convert inputs
inputs := make([]*protobufs.PendingTransactionInput, len(p.Inputs))
for i, input := range p.Inputs {
inputs[i] = input.ToProtobuf()
}
// Convert outputs
outputs := make([]*protobufs.PendingTransactionOutput, len(p.Outputs))
for i, output := range p.Outputs {
outputs[i] = output.ToProtobuf()
}
// Convert fees from []*big.Int to [][]byte
fees := make([][]byte, len(p.Fees))
for i, fee := range p.Fees {
if fee != nil {
fees[i] = fee.FillBytes(make([]byte, 32))
}
}
// Convert TraversalProof if present
var traversalProof *protobufs.TraversalProof
if p.TraversalProof != nil {
traversalProof = TraversalProofToProtobuf(p.TraversalProof)
}
return &protobufs.PendingTransaction{
Domain: p.Domain[:],
Inputs: inputs,
Outputs: outputs,
Fees: fees,
RangeProof: p.RangeProof,
TraversalProof: traversalProof,
}
}
// FromProtobuf converts a protobuf MintTransactionInput to intrinsics
// MintTransactionInput
func MintTransactionInputFromProtobuf(pb *protobufs.MintTransactionInput) (
*MintTransactionInput,
error,
) {
if pb == nil {
return nil, nil
}
// Convert value from bytes to big.Int
value := new(big.Int)
if len(pb.Value) > 0 {
value.SetBytes(pb.Value)
}
return &MintTransactionInput{
Value: value,
Commitment: pb.Commitment,
Signature: pb.Signature,
Proofs: pb.Proofs,
AdditionalReference: pb.AdditionalReference,
AdditionalReferenceKey: pb.AdditionalReferenceKey,
}, nil
}
// ToProtobuf converts an intrinsics MintTransactionInput to protobuf
// MintTransactionInput
func (m *MintTransactionInput) ToProtobuf() *protobufs.MintTransactionInput {
if m == nil {
return nil
}
var valueBytes []byte
if m.Value != nil {
valueBytes = m.Value.Bytes()
}
return &protobufs.MintTransactionInput{
Value: valueBytes,
Commitment: m.Commitment,
Signature: m.Signature,
Proofs: m.Proofs,
AdditionalReference: m.AdditionalReference,
AdditionalReferenceKey: m.AdditionalReferenceKey,
}
}
// FromProtobuf converts a protobuf MintTransactionOutput to intrinsics
// MintTransactionOutput
func MintTransactionOutputFromProtobuf(pb *protobufs.MintTransactionOutput) (
*MintTransactionOutput,
error,
) {
if pb == nil {
return nil, nil
}
recipientOutput, err := RecipientBundleFromProtobuf(pb.RecipientOutput)
if err != nil {
return nil, errors.Wrap(err, "converting recipient output")
}
return &MintTransactionOutput{
FrameNumber: pb.FrameNumber,
Commitment: pb.Commitment,
RecipientOutput: *recipientOutput,
}, nil
}
// ToProtobuf converts an intrinsics MintTransactionOutput to protobuf
// MintTransactionOutput
func (m *MintTransactionOutput) ToProtobuf() *protobufs.MintTransactionOutput {
if m == nil {
return nil
}
return &protobufs.MintTransactionOutput{
FrameNumber: m.FrameNumber,
Commitment: m.Commitment,
RecipientOutput: m.RecipientOutput.ToProtobuf(),
}
}
// FromProtobuf converts a protobuf MintTransaction to intrinsics
// MintTransaction
func MintTransactionFromProtobuf(pb *protobufs.MintTransaction) (
*MintTransaction,
error,
) {
if pb == nil {
return nil, nil
}
// Convert domain from slice to array
var domain [32]byte
copy(domain[:], pb.Domain)
// Convert inputs
inputs := make([]*MintTransactionInput, len(pb.Inputs))
for i, input := range pb.Inputs {
converted, err := MintTransactionInputFromProtobuf(input)
if err != nil {
return nil, errors.Wrapf(err, "converting input %d", i)
}
inputs[i] = converted
}
// Convert outputs
outputs := make([]*MintTransactionOutput, len(pb.Outputs))
for i, output := range pb.Outputs {
converted, err := MintTransactionOutputFromProtobuf(output)
if err != nil {
return nil, errors.Wrapf(err, "converting output %d", i)
}
outputs[i] = converted
}
// Convert fees from [][]byte to []*big.Int
fees := make([]*big.Int, len(pb.Fees))
for i, fee := range pb.Fees {
fees[i] = new(big.Int).SetBytes(fee)
}
return &MintTransaction{
Domain: domain,
Inputs: inputs,
Outputs: outputs,
Fees: fees,
RangeProof: pb.RangeProof,
// Runtime dependencies will be injected separately
}, nil
}
// ToProtobuf converts an intrinsics MintTransaction to protobuf MintTransaction
func (m *MintTransaction) ToProtobuf() *protobufs.MintTransaction {
if m == nil {
return nil
}
// Convert inputs
inputs := make([]*protobufs.MintTransactionInput, len(m.Inputs))
for i, input := range m.Inputs {
inputs[i] = input.ToProtobuf()
}
// Convert outputs
outputs := make([]*protobufs.MintTransactionOutput, len(m.Outputs))
for i, output := range m.Outputs {
outputs[i] = output.ToProtobuf()
}
// Convert fees from []*big.Int to [][]byte
fees := make([][]byte, len(m.Fees))
for i, fee := range m.Fees {
if fee != nil {
fees[i] = fee.Bytes()
}
}
return &protobufs.MintTransaction{
Domain: m.Domain[:],
Inputs: inputs,
Outputs: outputs,
Fees: fees,
RangeProof: m.RangeProof,
// Note: MintProof is not available in intrinsics structure
}
}
// TraversalProofToProtobuf converts qcrypto.TraversalProof to
// protobufs.TraversalProof
func TraversalProofToProtobuf(
tp *tries.TraversalProof,
) *protobufs.TraversalProof {
if tp == nil {
return nil
}
// Convert Multiproof
var multiproof *protobufs.Multiproof
if tp.Multiproof != nil {
multiproofBytes, _ := tp.Multiproof.ToBytes()
// Split the bytes - assuming first part is multicommitment, rest is proof
// This needs to match how the Multiproof is serialized
if len(multiproofBytes) > 0 {
multiproof = &protobufs.Multiproof{
Multicommitment: multiproofBytes[:min(74, len(multiproofBytes))],
Proof: multiproofBytes[min(74, len(multiproofBytes)):],
}
}
}
// Convert SubProofs
var subProofs []*protobufs.TraversalSubProof
for _, sp := range tp.SubProofs {
// Convert paths from [][]uint64 to []*protobufs.Path
var paths []*protobufs.Path
for _, path := range sp.Paths {
paths = append(paths, &protobufs.Path{
Indices: path,
})
}
subProofs = append(subProofs, &protobufs.TraversalSubProof{
Commits: sp.Commits,
Ys: sp.Ys,
Paths: paths,
})
}
return &protobufs.TraversalProof{
Multiproof: multiproof,
SubProofs: subProofs,
}
}
// TraversalProofFromProtobuf converts protobufs.TraversalProof to
// qcrypto.TraversalProof
func TraversalProofFromProtobuf(
pb *protobufs.TraversalProof,
inclusionProver crypto.InclusionProver,
) (*tries.TraversalProof, error) {
if pb == nil {
return nil, nil
}
tp := &tries.TraversalProof{}
// Convert Multiproof if present
if pb.Multiproof != nil && inclusionProver != nil {
mp := inclusionProver.NewMultiproof()
// Reconstruct the multiproof from its components
multiproofBytes := append(
pb.Multiproof.Multicommitment,
pb.Multiproof.Proof...,
)
if err := mp.FromBytes(multiproofBytes); err != nil {
return nil, errors.Wrap(err, "deserializing multiproof")
}
tp.Multiproof = mp
}
// Convert SubProofs
for _, pbSubProof := range pb.SubProofs {
// Convert paths from []*protobufs.Path to [][]uint64
var paths [][]uint64
for _, path := range pbSubProof.Paths {
paths = append(paths, path.Indices)
}
tp.SubProofs = append(tp.SubProofs, tries.TraversalSubProof{
Commits: pbSubProof.Commits,
Ys: pbSubProof.Ys,
Paths: paths,
})
}
return tp, nil
}