diff --git a/ledger/allegra.go b/ledger/allegra.go index a9f0679b..112c5705 100644 --- a/ledger/allegra.go +++ b/ledger/allegra.go @@ -158,6 +158,10 @@ func (t AllegraTransaction) ReferenceInputs() []TransactionInput { return t.Body.ReferenceInputs() } +func (t AllegraTransaction) Certificates() []Certificate { + return t.Body.Certificates() +} + func (t AllegraTransaction) Metadata() *cbor.Value { return t.TxMetadata } diff --git a/ledger/alonzo.go b/ledger/alonzo.go index 0c431432..2f7da50a 100644 --- a/ledger/alonzo.go +++ b/ledger/alonzo.go @@ -255,6 +255,10 @@ func (t AlonzoTransaction) ReferenceInputs() []TransactionInput { return t.Body.ReferenceInputs() } +func (t AlonzoTransaction) Certificates() []Certificate { + return t.Body.Certificates() +} + func (t AlonzoTransaction) Metadata() *cbor.Value { return t.TxMetadata } diff --git a/ledger/babbage.go b/ledger/babbage.go index 141fedd3..8f434745 100644 --- a/ledger/babbage.go +++ b/ledger/babbage.go @@ -430,6 +430,10 @@ func (t BabbageTransaction) ReferenceInputs() []TransactionInput { return t.Body.ReferenceInputs() } +func (t BabbageTransaction) Certificates() []Certificate { + return t.Body.Certificates() +} + func (t BabbageTransaction) Metadata() *cbor.Value { return t.TxMetadata } diff --git a/ledger/byron.go b/ledger/byron.go index 5aa6b580..65d3cdca 100644 --- a/ledger/byron.go +++ b/ledger/byron.go @@ -175,6 +175,11 @@ func (t *ByronTransaction) ReferenceInputs() []TransactionInput { return nil } +func (t *ByronTransaction) Certificates() []Certificate { + // TODO + return nil +} + func (t *ByronTransaction) Metadata() *cbor.Value { return t.Attributes } diff --git a/ledger/certificate.go b/ledger/certificate.go new file mode 100644 index 00000000..c5dfa0b3 --- /dev/null +++ b/ledger/certificate.go @@ -0,0 +1,195 @@ +// Copyright 2024 Blink Labs, LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ledger + +import ( + "fmt" + + utxorpc "github.com/utxorpc/go-codegen/utxorpc/v1alpha/cardano" + + "github.com/blinklabs-io/gouroboros/cbor" +) + +const ( + CertificateTypeStakeRegistration = 0 + CertificateTypeStakeDeregistration = 1 + CertificateTypeStakeDelegation = 2 + CertificateTypePoolRegistration = 3 + CertificateTypePoolRetirement = 4 + CertificateTypeGenesisKeyDelegation = 5 + CertificateTypeMoveInstantaneous = 6 +) + +type Certificate interface { + Cbor() []byte + CertificateType() uint + Data() *cbor.Value + Utxorpc() *utxorpc.Certificate +} + +const ( + StakeCredentialTypeAddrKeyHash = 0 + StakeCredentialTypeScriptHash = 1 +) + +type StakeCredential struct { + cbor.StructAsArray + cbor.DecodeStoreCbor + credType uint + StakeCredential []byte +} + +func NewStakeCredentialFromCbor(credType uint, data []byte) (StakeCredential, error) { + cred := StakeCredential{} + switch credType { + case StakeCredentialTypeAddrKeyHash: + // TODO: do this + return cred, nil + case StakeCredentialTypeScriptHash: + // TODO: do this + return cred, nil + } + return cred, fmt.Errorf("unknown stake credential type: %d", credType) +} + +type StakeRegistrationCertificate struct { + cbor.StructAsArray + cbor.DecodeStoreCbor + certType uint + StakeRegistration StakeCredential +} + +func NewStakeRegistrationCertificateFromCbor(credType uint, data []byte) (StakeCredential, error) { + cred := StakeCredential{ + credType: credType, + } + switch credType { + case StakeCredentialTypeAddrKeyHash: + // TODO: do this + return cred, nil + case StakeCredentialTypeScriptHash: + // TODO: do this + return cred, nil + } + return cred, fmt.Errorf("unknown stake credential type: %d", credType) +} + +func (c *StakeRegistrationCertificate) UnmarshalCBOR(cborData []byte) error { + return c.UnmarshalCbor(cborData, c) +} + +func (c *StakeRegistrationCertificate) CertificateType() uint { + return c.certType +} + +type StakeDeregistrationCertificate struct { + cbor.StructAsArray + cbor.DecodeStoreCbor + certType uint + StakeDeregistration *StakeCredential +} + +func (c *StakeDeregistrationCertificate) UnmarshalCBOR(cborData []byte) error { + return c.UnmarshalCbor(cborData, c) +} + +func (c *StakeDeregistrationCertificate) CertificateType() uint { + return c.certType +} + +type StakeDelegationCertificate struct { + cbor.StructAsArray + cbor.DecodeStoreCbor + certType uint + credential *StakeCredential + poolHash PoolKeyHash +} + +type AddrKeyHash Blake2b224 +type PoolKeyHash Blake2b224 +type PoolMetadataHash Blake2b256 +type VrfKeyHash Blake2b256 + +type RationalNumber struct { + Numerator uint64 + Denominator uint64 +} + +type PoolMetadata struct { + cbor.StructAsArray + url string + hash PoolMetadataHash +} + +type Relay struct { + cbor.StructAsArray + // TODO: create different relay shapes + _ interface{} +} + +type PoolRegistrationCertificate struct { + cbor.StructAsArray + cbor.DecodeStoreCbor + certType uint + Operator PoolKeyHash + VrfKeyHash VrfKeyHash + Pledge uint64 + Cost uint64 + Margin RationalNumber + RewardAccount AddrKeyHash + PoolOwners []AddrKeyHash + Relays []Relay + PoolMetadata *PoolMetadata +} + +type PoolRetirementCertificate struct { + cbor.StructAsArray + cbor.DecodeStoreCbor + certType uint + PoolKeyHash PoolKeyHash + Epoch uint64 +} + +type GenesisKeyDelegationCertificate struct { + cbor.StructAsArray + cbor.DecodeStoreCbor + certType uint + GenesisHash []byte + GenesisDelegateHash []byte + VrfKeyHash VrfKeyHash +} + +type MirSource int32 + +const ( + MirSourceUnspecified MirSource = 0 + MirSourceReserves MirSource = 1 + MirSourceTreasury MirSource = 2 +) + +type MirTarget struct { + cbor.StructAsArray + StakeCredential *StakeCredential + DeltaCoin int64 +} + +type MoveInstantaneousCertificate struct { + cbor.StructAsArray + cbor.DecodeStoreCbor + certType uint + From MirSource + To []*MirTarget + OtherPot uint64 +} diff --git a/ledger/conway.go b/ledger/conway.go index 562e8266..2f4dd88e 100644 --- a/ledger/conway.go +++ b/ledger/conway.go @@ -164,6 +164,10 @@ func (t ConwayTransaction) ReferenceInputs() []TransactionInput { return t.Body.ReferenceInputs() } +func (t ConwayTransaction) Certificates() []Certificate { + return t.Body.Certificates() +} + func (t ConwayTransaction) Metadata() *cbor.Value { return t.TxMetadata } diff --git a/ledger/mary.go b/ledger/mary.go index db250408..5534a188 100644 --- a/ledger/mary.go +++ b/ledger/mary.go @@ -164,6 +164,10 @@ func (t MaryTransaction) ReferenceInputs() []TransactionInput { return t.Body.ReferenceInputs() } +func (t MaryTransaction) Certificates() []Certificate { + return t.Body.Certificates() +} + func (t MaryTransaction) Metadata() *cbor.Value { return t.TxMetadata } diff --git a/ledger/shelley.go b/ledger/shelley.go index d4ef91bb..531803b4 100644 --- a/ledger/shelley.go +++ b/ledger/shelley.go @@ -162,13 +162,12 @@ func (h *ShelleyBlockHeader) Era() Era { type ShelleyTransactionBody struct { cbor.DecodeStoreCbor - hash string - TxInputs []ShelleyTransactionInput `cbor:"0,keyasint,omitempty"` - TxOutputs []ShelleyTransactionOutput `cbor:"1,keyasint,omitempty"` - TxFee uint64 `cbor:"2,keyasint,omitempty"` - Ttl uint64 `cbor:"3,keyasint,omitempty"` - // TODO: figure out how to parse properly - Certificates cbor.RawMessage `cbor:"4,keyasint,omitempty"` + hash string + TxInputs []ShelleyTransactionInput `cbor:"0,keyasint,omitempty"` + TxOutputs []ShelleyTransactionOutput `cbor:"1,keyasint,omitempty"` + TxFee uint64 `cbor:"2,keyasint,omitempty"` + Ttl uint64 `cbor:"3,keyasint,omitempty"` + TxCertificates []Certificate `cbor:"4,keyasint,omitempty"` // TODO: figure out how to parse this correctly // We keep the raw CBOR because it can contain a map with []byte keys, which // Go does not allow @@ -221,6 +220,10 @@ func (b *ShelleyTransactionBody) ReferenceInputs() []TransactionInput { return []TransactionInput{} } +func (b *ShelleyTransactionBody) Certificates() []Certificate { + return b.TxCertificates +} + func (b *ShelleyTransactionBody) Utxorpc() *utxorpc.Tx { var txi []*utxorpc.TxInput var txo []*utxorpc.TxOutput @@ -359,6 +362,10 @@ func (t ShelleyTransaction) ReferenceInputs() []TransactionInput { return t.Body.ReferenceInputs() } +func (t ShelleyTransaction) Certificates() []Certificate { + return t.Body.Certificates() +} + func (t ShelleyTransaction) Metadata() *cbor.Value { return t.TxMetadata } diff --git a/ledger/tx.go b/ledger/tx.go index 0532d349..1f58395d 100644 --- a/ledger/tx.go +++ b/ledger/tx.go @@ -38,6 +38,7 @@ type TransactionBody interface { Outputs() []TransactionOutput TTL() uint64 ReferenceInputs() []TransactionInput + Certificates() []Certificate Utxorpc() *utxorpc.Tx }