From 0afcd31a9ff49bd2ffed898dac5fd56c3a297ddc Mon Sep 17 00:00:00 2001 From: Aurora Gaffney Date: Fri, 29 Aug 2025 15:23:56 -0400 Subject: [PATCH] feat: support for certificates in plutus script context * implement ToPlutusData() for common.Drep * rename stake registration/deregistration field for consistency * support for certificates and treasury amount/donation in TxInfoV3 * port Aiken script_context_certificates test Fixes #1102 Signed-off-by: Aurora Gaffney --- internal/test/ledger/ledger.go | 2 +- ledger/allegra/rules_test.go | 4 +- ledger/alonzo/rules_test.go | 4 +- ledger/babbage/rules_test.go | 4 +- ledger/common/certs.go | 45 +++++-- ledger/common/script/context.go | 171 ++++++++++++++++++++++++--- ledger/common/script/context_test.go | 9 ++ ledger/common/script/purpose.go | 54 ++++++++- ledger/common/script/wrappers.go | 12 +- ledger/conway/rules_test.go | 4 +- ledger/mary/rules_test.go | 4 +- ledger/shelley/rules_test.go | 4 +- 12 files changed, 270 insertions(+), 47 deletions(-) diff --git a/internal/test/ledger/ledger.go b/internal/test/ledger/ledger.go index dff9a789..7382cc21 100644 --- a/internal/test/ledger/ledger.go +++ b/internal/test/ledger/ledger.go @@ -52,7 +52,7 @@ func (ls MockLedgerState) StakeRegistration( ret := []common.StakeRegistrationCertificate{} for _, cert := range ls.MockStakeRegistration { if string( - common.Blake2b224(cert.StakeRegistration.Credential).Bytes(), + common.Blake2b224(cert.StakeCredential.Credential).Bytes(), ) == string( stakingKey, ) { diff --git a/ledger/allegra/rules_test.go b/ledger/allegra/rules_test.go index 10c3abe0..78811803 100644 --- a/ledger/allegra/rules_test.go +++ b/ledger/allegra/rules_test.go @@ -554,7 +554,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) { { Type: common.CertificateTypeStakeRegistration, Certificate: &common.StakeRegistrationCertificate{ - StakeRegistration: common.Credential{}, + StakeCredential: common.Credential{}, }, }, } @@ -581,7 +581,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) { { Type: common.CertificateTypeStakeRegistration, Certificate: &common.StakeDeregistrationCertificate{ - StakeDeregistration: common.Credential{}, + StakeCredential: common.Credential{}, }, }, } diff --git a/ledger/alonzo/rules_test.go b/ledger/alonzo/rules_test.go index a6426fbf..ccdb6071 100644 --- a/ledger/alonzo/rules_test.go +++ b/ledger/alonzo/rules_test.go @@ -563,7 +563,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) { { Type: common.CertificateTypeStakeRegistration, Certificate: &common.StakeRegistrationCertificate{ - StakeRegistration: common.Credential{}, + StakeCredential: common.Credential{}, }, }, } @@ -590,7 +590,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) { { Type: common.CertificateTypeStakeRegistration, Certificate: &common.StakeDeregistrationCertificate{ - StakeDeregistration: common.Credential{}, + StakeCredential: common.Credential{}, }, }, } diff --git a/ledger/babbage/rules_test.go b/ledger/babbage/rules_test.go index 58ea7e7c..01957229 100644 --- a/ledger/babbage/rules_test.go +++ b/ledger/babbage/rules_test.go @@ -564,7 +564,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) { { Type: common.CertificateTypeStakeRegistration, Certificate: &common.StakeRegistrationCertificate{ - StakeRegistration: common.Credential{}, + StakeCredential: common.Credential{}, }, }, } @@ -591,7 +591,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) { { Type: common.CertificateTypeStakeRegistration, Certificate: &common.StakeDeregistrationCertificate{ - StakeDeregistration: common.Credential{}, + StakeCredential: common.Credential{}, }, }, } diff --git a/ledger/common/certs.go b/ledger/common/certs.go index aa257ab2..7ca75717 100644 --- a/ledger/common/certs.go +++ b/ledger/common/certs.go @@ -22,6 +22,7 @@ import ( "net" "github.com/blinklabs-io/gouroboros/cbor" + "github.com/blinklabs-io/plutigo/data" utxorpc "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" ) @@ -159,11 +160,37 @@ func (d *Drep) UnmarshalCBOR(data []byte) error { return nil } +func (d *Drep) ToPlutusData() data.PlutusData { + switch d.Type { + case DrepTypeAddrKeyHash: + return data.NewConstr( + 0, + data.NewConstr( + 0, + data.NewByteString(d.Credential), + ), + ) + case DrepTypeScriptHash: + return data.NewConstr( + 0, + data.NewConstr( + 1, + data.NewByteString(d.Credential), + ), + ) + case DrepTypeAbstain: + return data.NewConstr(1) + case DrepTypeNoConfidence: + return data.NewConstr(2) + } + return nil +} + type StakeRegistrationCertificate struct { cbor.StructAsArray cbor.DecodeStoreCbor - CertType uint - StakeRegistration Credential + CertType uint + StakeCredential Credential } func (c StakeRegistrationCertificate) isCertificate() {} @@ -180,7 +207,7 @@ func (c *StakeRegistrationCertificate) UnmarshalCBOR(cborData []byte) error { } func (c *StakeRegistrationCertificate) Utxorpc() (*utxorpc.Certificate, error) { - stakeCred, err := c.StakeRegistration.Utxorpc() + stakeCred, err := c.StakeCredential.Utxorpc() if err != nil { return nil, err } @@ -198,8 +225,8 @@ func (c *StakeRegistrationCertificate) Type() uint { type StakeDeregistrationCertificate struct { cbor.StructAsArray cbor.DecodeStoreCbor - CertType uint - StakeDeregistration Credential + CertType uint + StakeCredential Credential } func (c StakeDeregistrationCertificate) isCertificate() {} @@ -216,7 +243,7 @@ func (c *StakeDeregistrationCertificate) UnmarshalCBOR(cborData []byte) error { } func (c *StakeDeregistrationCertificate) Utxorpc() (*utxorpc.Certificate, error) { - stakeDeReg, err := c.StakeDeregistration.Utxorpc() + stakeDeReg, err := c.StakeCredential.Utxorpc() if err != nil { return nil, err } @@ -1081,7 +1108,7 @@ type AuthCommitteeHotCertificate struct { cbor.DecodeStoreCbor CertType uint ColdCredential Credential - HostCredential Credential + HotCredential Credential } func (c AuthCommitteeHotCertificate) isCertificate() {} @@ -1104,7 +1131,7 @@ func (c *AuthCommitteeHotCertificate) Utxorpc() (*utxorpc.Certificate, error) { if err != nil { return nil, err } - hostCred, err := c.HostCredential.Utxorpc() + hotCred, err := c.HotCredential.Utxorpc() if err != nil { return nil, err } @@ -1112,7 +1139,7 @@ func (c *AuthCommitteeHotCertificate) Utxorpc() (*utxorpc.Certificate, error) { Certificate: &utxorpc.Certificate_AuthCommitteeHotCert{ AuthCommitteeHotCert: &utxorpc.AuthCommitteeHotCert{ CommitteeColdCredential: coldCred, - CommitteeHotCredential: hostCred, + CommitteeHotCredential: hotCred, }, }, }, nil diff --git a/ledger/common/script/context.go b/ledger/common/script/context.go index 3f5d974f..50602166 100644 --- a/ledger/common/script/context.go +++ b/ledger/common/script/context.go @@ -153,8 +153,7 @@ func (t TxInfoV3) ToPlutusData() data.PlutusData { toPlutusData(t.Outputs), data.NewInteger(new(big.Int).SetUint64(t.Fee)), t.Mint.ToPlutusData(), - // TODO: certs - toPlutusData([]any{}), + certificatesToPlutusData(t.Certificates), toPlutusData(t.Withdrawals), t.ValidRange.ToPlutusData(), toPlutusData(t.Signatories), @@ -165,10 +164,8 @@ func (t TxInfoV3) ToPlutusData() data.PlutusData { data.NewMap([][2]data.PlutusData{}), // TODO: proposal procedures toPlutusData([]any{}), - // TODO: current treasury amount - data.NewConstr(1), - // TODO: treasury donation - data.NewConstr(1), + t.CurrentTreasuryAmount.ToPlutusData(), + t.TreasuryDonation.ToPlutusData(), ) } @@ -187,7 +184,7 @@ func NewTxInfoV3FromTransaction( resolvedInputs, inputs, *assetMint, - // TODO: certificates + tx.Certificates(), tx.Withdrawals(), // TODO: proposal procedures // TODO: votes @@ -207,15 +204,20 @@ func NewTxInfoV3FromTransaction( tx.TTL(), tx.ValidityIntervalStart(), }, - Withdrawals: tx.Withdrawals(), - Signatories: signatoriesInfo(tx.RequiredSigners()), - Redeemers: redeemers, - Data: tmpData, - Id: tx.Hash(), + Certificates: tx.Certificates(), + Withdrawals: tx.Withdrawals(), + Signatories: signatoriesInfo(tx.RequiredSigners()), + Redeemers: redeemers, + Data: tmpData, + Id: tx.Hash(), // TODO: Votes // TODO: ProposalProcedures - // TODO: CurrentTreasuryAmount - // TODO: TreasuryDonation + } + if amt := tx.CurrentTreasuryValue(); amt > 0 { + ret.CurrentTreasuryAmount.Value = amt + } + if amt := tx.Donation(); amt > 0 { + ret.TreasuryDonation.Value = amt } return ret } @@ -396,3 +398,144 @@ func signatoriesInfo( ) return tmp } + +func certificatesToPlutusData( + certificates []lcommon.Certificate, +) data.PlutusData { + tmpCerts := make([]data.PlutusData, len(certificates)) + for idx, cert := range certificates { + tmpCerts[idx] = certificateToPlutusData(cert) + } + return data.NewList(tmpCerts...) +} + +func certificateToPlutusData( + certificate lcommon.Certificate, +) data.PlutusData { + switch c := certificate.(type) { + case *lcommon.StakeRegistrationCertificate: + return data.NewConstr( + 0, + c.StakeCredential.ToPlutusData(), + data.NewConstr(1), + ) + case *lcommon.RegistrationCertificate: + return data.NewConstr( + 0, + c.StakeCredential.ToPlutusData(), + data.NewConstr(1), + ) + case *lcommon.StakeDeregistrationCertificate: + return data.NewConstr( + 1, + c.StakeCredential.ToPlutusData(), + data.NewConstr(1), + ) + case *lcommon.DeregistrationCertificate: + return data.NewConstr( + 1, + c.StakeCredential.ToPlutusData(), + data.NewConstr(1), + ) + case *lcommon.StakeDelegationCertificate: + return data.NewConstr( + 2, + c.StakeCredential.ToPlutusData(), + data.NewConstr( + 0, + c.PoolKeyHash.ToPlutusData(), + ), + ) + case *lcommon.VoteDelegationCertificate: + return data.NewConstr( + 2, + c.StakeCredential.ToPlutusData(), + data.NewConstr( + 1, + c.Drep.ToPlutusData(), + ), + ) + case *lcommon.StakeVoteDelegationCertificate: + return data.NewConstr( + 2, + c.StakeCredential.ToPlutusData(), + data.NewConstr( + 2, + toPlutusData(c.PoolKeyHash), + c.Drep.ToPlutusData(), + ), + ) + case *lcommon.StakeRegistrationDelegationCertificate: + return data.NewConstr( + 3, + c.StakeCredential.ToPlutusData(), + data.NewConstr( + 0, + toPlutusData(c.PoolKeyHash), + ), + data.NewInteger(big.NewInt(c.Amount)), + ) + case *lcommon.VoteRegistrationDelegationCertificate: + return data.NewConstr( + 3, + c.StakeCredential.ToPlutusData(), + data.NewConstr( + 1, + c.Drep.ToPlutusData(), + ), + data.NewInteger(big.NewInt(c.Amount)), + ) + case *lcommon.StakeVoteRegistrationDelegationCertificate: + return data.NewConstr( + 3, + c.StakeCredential.ToPlutusData(), + data.NewConstr( + 2, + c.PoolKeyHash.ToPlutusData(), + c.Drep.ToPlutusData(), + ), + data.NewInteger(big.NewInt(c.Amount)), + ) + case *lcommon.RegistrationDrepCertificate: + return data.NewConstr( + 4, + c.DrepCredential.ToPlutusData(), + data.NewInteger(big.NewInt(c.Amount)), + ) + case *lcommon.UpdateDrepCertificate: + return data.NewConstr( + 5, + c.DrepCredential.ToPlutusData(), + ) + case *lcommon.DeregistrationDrepCertificate: + return data.NewConstr( + 6, + c.DrepCredential.ToPlutusData(), + data.NewInteger(big.NewInt(c.Amount)), + ) + case *lcommon.PoolRegistrationCertificate: + return data.NewConstr( + 7, + toPlutusData(c.Operator), + toPlutusData(c.VrfKeyHash), + ) + case *lcommon.PoolRetirementCertificate: + return data.NewConstr( + 8, + toPlutusData(c.PoolKeyHash), + data.NewInteger(new(big.Int).SetUint64(c.Epoch)), + ) + case *lcommon.AuthCommitteeHotCertificate: + return data.NewConstr( + 9, + c.ColdCredential.ToPlutusData(), + c.HotCredential.ToPlutusData(), + ) + case *lcommon.ResignCommitteeColdCertificate: + return data.NewConstr( + 10, + c.ColdCredential.ToPlutusData(), + ) + } + return nil +} diff --git a/ledger/common/script/context_test.go b/ledger/common/script/context_test.go index 8ef47933..b588d143 100644 --- a/ledger/common/script/context_test.go +++ b/ledger/common/script/context_test.go @@ -186,6 +186,15 @@ var scriptContextV3TestDefs = []struct { redeemerIndex: 0, expectedCbor: "d8799fd8799f9fd8799fd8799f5820c9f355431b2546acfc03b11540dc8bee31b9afc5674081a61cc39e0845380e7a00ffd8799fd8799fd87a9f581cfdd6640d1c9a4392dd7e829f0cc4e26766539c48b2cf594959e33559ffd87a80ffa140a1401a00989680d87b9fd8799f581c9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e50ffffd8799f581cfdd6640d1c9a4392dd7e829f0cc4e26766539c48b2cf594959e33559ffffffff9fd8799fd8799f58204f184460ae3f3c15c6811f1380c3abc7bb73bf3cbbdffe874913c2410fc3577600ffd8799fd8799fd87a9f581cfdd6640d1c9a4392dd7e829f0cc4e26766539c48b2cf594959e33559ffd87a80ffa140a1401a00989680d87b9fd8799f581c86b74c779bb9cf43532b357323b0ced1bdd6aa4276c45aee845f33feffffd8799f581cfdd6640d1c9a4392dd7e829f0cc4e26766539c48b2cf594959e33559ffffffff9fd8799fd8799fd8799f581c9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e50ffd8799fd8799fd8799f581c5064b671634d14cb8d543e71dd8eb437a47efb47b0b22882866c420dffffffffa140a1401a009569e4d87980d87a80ffff1a00032c9ca080a0d8799fd8799fd87980d87a80ffd8799fd87b80d87a80ffff9f581c9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e50ffa1d87a9fd8799f5820c9f355431b2546acfc03b11540dc8bee31b9afc5674081a61cc39e0845380e7a00ffffd8799f4d48656c6c6f2c20576f726c6421ffa05820ac73d6545da30a8cc0395de0c2a5fa3ad99329f41d319901ebe2922f8554d5e3a080d87a80d87a80ffd8799f4d48656c6c6f2c20576f726c6421ffd87a9fd8799f5820c9f355431b2546acfc03b11540dc8bee31b9afc5674081a61cc39e0845380e7a00ffd8799fd8799f581c9fc430ea1f3adc20eebb813b2649e85c934ea5bc13d7b7fbe2b24e50ffffffff", }, + { + name: "Certificates", + txHex: "84a600818258200000000000000000000000000000000000000000000000000000000000000000000180049582008201581c2222222222222222222222222222222222222222222222222222222282008200581c0000000000000000000000000000000000000000000000000000000082018200581c000000000000000000000000000000000000000000000000000000008a03581c11111111111111111111111111111111111111111111111111111111582099999999999999999999999999999999999999999999999999999999999999991a000f4240190154d81e82011864581de000000000000000000000000000000000000000000000000000000000d901028080f68304581c1111111111111111111111111111111111111111111111111111111119053983078200581c000000000000000000000000000000000000000000000000000000001a002dc6c083088200581c000000000000000000000000000000000000000000000000000000001a002dc6c083098200581c000000000000000000000000000000000000000000000000000000008200581c0000000000000000000000000000000000000000000000000000000083098200581c000000000000000000000000000000000000000000000000000000008201581c0000000000000000000000000000000000000000000000000000000083098200581c00000000000000000000000000000000000000000000000000000000810283098200581c000000000000000000000000000000000000000000000000000000008103840a8200581c00000000000000000000000000000000000000000000000000000000581c111111111111111111111111111111111111111111111111111111118103840b8200581c00000000000000000000000000000000000000000000000000000000581c111111111111111111111111111111111111111111111111111111111a002dc6c0840c8200581c0000000000000000000000000000000000000000000000000000000081031a002dc6c0850d8200581c00000000000000000000000000000000000000000000000000000000581c1111111111111111111111111111111111111111111111111111111181031a002dc6c0830e8200581c000000000000000000000000000000000000000000000000000000008200581c22222222222222222222222222222222222222222222222222222222830f8200581c00000000000000000000000000000000000000000000000000000000f684108200581c000000000000000000000000000000000000000000000000000000001a002dc6c0f683118200581c000000000000000000000000000000000000000000000000000000001a002dc6c083128200581c00000000000000000000000000000000000000000000000000000000f683028201581c9b24324046544393443e1fb35c8b72c3c39e18a516a95df5f6654101581c1111111111111111111111111111111111111111111111111111111102182a151a00989680160ea20581840214d87980821a000f42401a05f5e1000781587d587b0101003232323232323225333333008001153330033370e900018029baa001153330073006375400224a66600894452615330054911856616c696461746f722072657475726e65642066616c73650013656002002002002002002153300249010b5f746d70313a20566f696400165734ae7155ceaab9e5573eae91f5f6", + inputsHex: "81825820000000000000000000000000000000000000000000000000000000000000000000", + outputsHex: "81a200581d6000000000000000000000000000000000000000000000000000000000011a000f4240", + redeemerTag: common.RedeemerTagCert, + redeemerIndex: 20, + expectedCbor: "d8799fd8799f9fd8799fd8799f5820000000000000000000000000000000000000000000000000000000000000000000ffd8799fd8799fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a80ffa140a1401a000f4240d87980d87a80ffffff8080182aa09fd8799fd87a9f581c22222222222222222222222222222222222222222222222222222222ffd87a80ffd8799fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a80ffd87a9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a80ffd905009f581c1111111111111111111111111111111111111111111111111111111158209999999999999999999999999999999999999999999999999999999999999999ffd905019f581c11111111111111111111111111111111111111111111111111111111190539ffd8799fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a80ffd87a9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a80ffd87b9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a9fd8799fd8799f581c00000000000000000000000000000000000000000000000000000000ffffffffd87b9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a9fd8799fd87a9f581c00000000000000000000000000000000000000000000000000000000ffffffffd87b9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a9fd87a80ffffd87b9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a9fd87b80ffffd87b9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87b9f581c11111111111111111111111111111111111111111111111111111111d87b80ffffd87c9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd8799f581c11111111111111111111111111111111111111111111111111111111ff1a002dc6c0ffd87c9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a9fd87b80ff1a002dc6c0ffd87c9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87b9f581c11111111111111111111111111111111111111111111111111111111d87b80ff1a002dc6c0ffd905029fd8799f581c00000000000000000000000000000000000000000000000000000000ffd8799f581c22222222222222222222222222222222222222222222222222222222ffffd905039fd8799f581c00000000000000000000000000000000000000000000000000000000ffffd87d9fd8799f581c00000000000000000000000000000000000000000000000000000000ff1a002dc6c0ffd87f9fd8799f581c00000000000000000000000000000000000000000000000000000000ff1a002dc6c0ffd87e9fd8799f581c00000000000000000000000000000000000000000000000000000000ffffd87b9fd87a9f581c9b24324046544393443e1fb35c8b72c3c39e18a516a95df5f6654101ffd8799f581c11111111111111111111111111111111111111111111111111111111ffffffa0d8799fd8799fd87980d87a80ffd8799fd87b80d87a80ffff80a1d87c9f14d87b9fd87a9f581c9b24324046544393443e1fb35c8b72c3c39e18a516a95df5f6654101ffd8799f581c11111111111111111111111111111111111111111111111111111111ffffffd87980a0582080bf68ced2c50b8734fc8cebd0a049e16e53d2fe5ec7e42822f07c263ced98aba080d8799f1a00989680ffd8799f0effffd87980d87c9f14d87b9fd87a9f581c9b24324046544393443e1fb35c8b72c3c39e18a516a95df5f6654101ffd8799f581c11111111111111111111111111111111111111111111111111111111ffffffff", + }, } func TestScriptContextV3(t *testing.T) { diff --git a/ledger/common/script/purpose.go b/ledger/common/script/purpose.go index 46cc3aa5..907ba33c 100644 --- a/ledger/common/script/purpose.go +++ b/ledger/common/script/purpose.go @@ -16,6 +16,7 @@ package script import ( "bytes" + "math/big" "slices" lcommon "github.com/blinklabs-io/gouroboros/ledger/common" @@ -91,20 +92,58 @@ func (s ScriptInfoRewarding) ToPlutusData() data.PlutusData { } type ScriptInfoCertifying struct { - Size uint64 + Index uint32 Certificate lcommon.Certificate } func (ScriptInfoCertifying) isScriptInfo() {} func (s ScriptInfoCertifying) ScriptHash() lcommon.ScriptHash { - // TODO + var cred *lcommon.Credential + switch c := s.Certificate.(type) { + case *lcommon.StakeDeregistrationCertificate: + cred = &c.StakeCredential + case *lcommon.RegistrationCertificate: + cred = &c.StakeCredential + case *lcommon.DeregistrationCertificate: + cred = &c.StakeCredential + case *lcommon.VoteDelegationCertificate: + cred = &c.StakeCredential + case *lcommon.VoteRegistrationDelegationCertificate: + cred = &c.StakeCredential + case *lcommon.StakeVoteDelegationCertificate: + cred = &c.StakeCredential + case *lcommon.StakeRegistrationDelegationCertificate: + cred = &c.StakeCredential + case *lcommon.StakeVoteRegistrationDelegationCertificate: + cred = &c.StakeCredential + case *lcommon.RegistrationDrepCertificate: + cred = &c.DrepCredential + case *lcommon.DeregistrationDrepCertificate: + cred = &c.DrepCredential + case *lcommon.UpdateDrepCertificate: + cred = &c.DrepCredential + case *lcommon.AuthCommitteeHotCertificate: + cred = &c.ColdCredential + case *lcommon.ResignCommitteeColdCertificate: + cred = &c.ColdCredential + case *lcommon.StakeDelegationCertificate: + cred = c.StakeCredential + } + if cred != nil { + if cred.CredType == lcommon.CredentialTypeScriptHash { + return cred.Credential + } + } return lcommon.ScriptHash{} } func (s ScriptInfoCertifying) ToPlutusData() data.PlutusData { - // TODO - return nil + return data.NewConstr( + 3, + data.NewInteger(new(big.Int).SetUint64(uint64(s.Index))), + certificateToPlutusData(s.Certificate), + ) } type ScriptInfoVoting struct { @@ -147,7 +186,7 @@ func scriptPurposeBuilder( resolvedInputs []lcommon.Utxo, inputs []lcommon.TransactionInput, mint lcommon.MultiAsset[lcommon.MultiAssetTypeMint], - // TODO: certificates + certificates []lcommon.Certificate, withdrawals map[*lcommon.Address]uint64, // TODO: proposal procedures // TODO: votes @@ -184,7 +223,10 @@ func scriptPurposeBuilder( PolicyId: mintPolicies[redeemerKey.Index], } case lcommon.RedeemerTagCert: - return nil + return ScriptInfoCertifying{ + Index: redeemerKey.Index, + Certificate: certificates[redeemerKey.Index], + } case lcommon.RedeemerTagReward: return nil case lcommon.RedeemerTagVoting: diff --git a/ledger/common/script/wrappers.go b/ledger/common/script/wrappers.go index 9dd92330..a6305f5d 100644 --- a/ledger/common/script/wrappers.go +++ b/ledger/common/script/wrappers.go @@ -27,17 +27,17 @@ type ToPlutusData interface { ToPlutusData() data.PlutusData } -type Option[T ToPlutusData] struct { - Value ToPlutusData +type Option[T any] struct { + Value any } func (o Option[T]) ToPlutusData() data.PlutusData { if o.Value == nil { - return data.NewConstr(0) + return data.NewConstr(1) } return data.NewConstr( - 1, - o.Value.ToPlutusData(), + 0, + toPlutusData(o.Value), ) } @@ -79,6 +79,8 @@ func toPlutusData(val any) data.PlutusData { tmpItems[i] = item.ToPlutusData() } return data.NewList(tmpItems...) + case []byte: + return data.NewByteString(v) case data.PlutusData: return v default: diff --git a/ledger/conway/rules_test.go b/ledger/conway/rules_test.go index 377767a0..30994281 100644 --- a/ledger/conway/rules_test.go +++ b/ledger/conway/rules_test.go @@ -562,7 +562,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) { { Type: common.CertificateTypeStakeRegistration, Certificate: &common.StakeRegistrationCertificate{ - StakeRegistration: common.Credential{}, + StakeCredential: common.Credential{}, }, }, } @@ -589,7 +589,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) { { Type: common.CertificateTypeStakeRegistration, Certificate: &common.StakeDeregistrationCertificate{ - StakeDeregistration: common.Credential{}, + StakeCredential: common.Credential{}, }, }, } diff --git a/ledger/mary/rules_test.go b/ledger/mary/rules_test.go index 8e6754c4..e83cebb3 100644 --- a/ledger/mary/rules_test.go +++ b/ledger/mary/rules_test.go @@ -561,7 +561,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) { { Type: common.CertificateTypeStakeRegistration, Certificate: &common.StakeRegistrationCertificate{ - StakeRegistration: common.Credential{}, + StakeCredential: common.Credential{}, }, }, } @@ -588,7 +588,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) { { Type: common.CertificateTypeStakeRegistration, Certificate: &common.StakeDeregistrationCertificate{ - StakeDeregistration: common.Credential{}, + StakeCredential: common.Credential{}, }, }, } diff --git a/ledger/shelley/rules_test.go b/ledger/shelley/rules_test.go index 87d1b6b6..ba016421 100644 --- a/ledger/shelley/rules_test.go +++ b/ledger/shelley/rules_test.go @@ -553,7 +553,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) { { Type: common.CertificateTypeStakeRegistration, Certificate: &common.StakeRegistrationCertificate{ - StakeRegistration: common.Credential{}, + StakeCredential: common.Credential{}, }, }, } @@ -580,7 +580,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) { { Type: common.CertificateTypeStakeRegistration, Certificate: &common.StakeDeregistrationCertificate{ - StakeDeregistration: common.Credential{}, + StakeCredential: common.Credential{}, }, }, }