From f830a6237dbdf66a6b038f4a0ecc3b82c5df5fd8 Mon Sep 17 00:00:00 2001 From: Aurora Gaffney Date: Wed, 15 May 2024 14:51:16 -0500 Subject: [PATCH] feat: TX proposal procedures attribute This adds support for decoding and retrieving governance proposal procedures from a TX Fixes #344 --- ledger/allegra.go | 4 ++ ledger/alonzo.go | 4 ++ ledger/babbage.go | 4 ++ ledger/byron.go | 5 ++ ledger/conway.go | 152 ++++++++++++++++++++++++++++++++++++++++++++-- ledger/mary.go | 4 ++ ledger/shelley.go | 9 +++ ledger/tx.go | 1 + 8 files changed, 179 insertions(+), 4 deletions(-) diff --git a/ledger/allegra.go b/ledger/allegra.go index 099413ec..fbf4ed43 100644 --- a/ledger/allegra.go +++ b/ledger/allegra.go @@ -182,6 +182,10 @@ func (t AllegraTransaction) VotingProcedures() VotingProcedures { return t.Body.VotingProcedures() } +func (t AllegraTransaction) ProposalProcedures() []ProposalProcedure { + return t.Body.ProposalProcedures() +} + func (t AllegraTransaction) Metadata() *cbor.Value { return t.TxMetadata } diff --git a/ledger/alonzo.go b/ledger/alonzo.go index c052c510..38988db3 100644 --- a/ledger/alonzo.go +++ b/ledger/alonzo.go @@ -292,6 +292,10 @@ func (t AlonzoTransaction) VotingProcedures() VotingProcedures { return t.Body.VotingProcedures() } +func (t AlonzoTransaction) ProposalProcedures() []ProposalProcedure { + return t.Body.ProposalProcedures() +} + func (t AlonzoTransaction) Metadata() *cbor.Value { return t.TxMetadata } diff --git a/ledger/babbage.go b/ledger/babbage.go index 70f6550a..d0d1edfc 100644 --- a/ledger/babbage.go +++ b/ledger/babbage.go @@ -468,6 +468,10 @@ func (t BabbageTransaction) VotingProcedures() VotingProcedures { return t.Body.VotingProcedures() } +func (t BabbageTransaction) ProposalProcedures() []ProposalProcedure { + return t.Body.ProposalProcedures() +} + func (t BabbageTransaction) Metadata() *cbor.Value { return t.TxMetadata } diff --git a/ledger/byron.go b/ledger/byron.go index 56dba496..70116d96 100644 --- a/ledger/byron.go +++ b/ledger/byron.go @@ -205,6 +205,11 @@ func (t *ByronTransaction) VotingProcedures() VotingProcedures { return nil } +func (t *ByronTransaction) ProposalProcedures() []ProposalProcedure { + // No proposal procedures in Byron + return nil +} + func (t *ByronTransaction) Metadata() *cbor.Value { return t.Attributes } diff --git a/ledger/conway.go b/ledger/conway.go index b6a71e41..c8ead3d1 100644 --- a/ledger/conway.go +++ b/ledger/conway.go @@ -121,10 +121,10 @@ func (h *ConwayBlockHeader) Era() Era { type ConwayTransactionBody struct { BabbageTransactionBody - TxVotingProcedures VotingProcedures `cbor:"19,keyasint,omitempty"` - ProposalProcedures *cbor.Value `cbor:"20,keyasint,omitempty"` - CurrentTreasuryValue int64 `cbor:"21,keyasint,omitempty"` - Donation uint64 `cbor:"22,keyasint,omitempty"` + TxVotingProcedures VotingProcedures `cbor:"19,keyasint,omitempty"` + TxProposalProcedures []ProposalProcedure `cbor:"20,keyasint,omitempty"` + CurrentTreasuryValue int64 `cbor:"21,keyasint,omitempty"` + Donation uint64 `cbor:"22,keyasint,omitempty"` } func (b *ConwayTransactionBody) UnmarshalCBOR(cborData []byte) error { @@ -135,6 +135,10 @@ func (b *ConwayTransactionBody) VotingProcedures() VotingProcedures { return b.TxVotingProcedures } +func (b *ConwayTransactionBody) ProposalProcedures() []ProposalProcedure { + return b.TxProposalProcedures +} + // VotingProcedures is a convenience type to avoid needing to duplicate the full type definition everywhere type VotingProcedures map[*Voter]map[*GovActionId]VotingProcedure @@ -176,6 +180,142 @@ type GovActionId struct { GovActionIdx uint32 } +type ProposalProcedure struct { + cbor.StructAsArray + Deposit uint64 + RewardAccount Address + GovAction GovActionWrapper + Anchor GovAnchor +} + +const ( + GovActionTypeParameterChange = 0 + GovActionTypeHardForkInitiation = 1 + GovActionTypeTreasuryWithdrawal = 2 + GovActionTypeNoConfidence = 3 + GovActionTypeUpdateCommittee = 4 + GovActionTypeNewConstitution = 5 + GovActionTypeInfo = 6 +) + +type GovActionWrapper struct { + Type uint + Action GovAction +} + +func (g *GovActionWrapper) UnmarshalCBOR(data []byte) error { + // Determine action type + actionType, err := cbor.DecodeIdFromList(data) + if err != nil { + return err + } + var tmpAction GovAction + switch actionType { + case GovActionTypeParameterChange: + tmpAction = &ParameterChangeGovAction{} + case GovActionTypeHardForkInitiation: + tmpAction = &HardForkInitiationGovAction{} + case GovActionTypeTreasuryWithdrawal: + tmpAction = &TreasuryWithdrawalGovAction{} + case GovActionTypeNoConfidence: + tmpAction = &NoConfidenceGovAction{} + case GovActionTypeUpdateCommittee: + tmpAction = &UpdateCommitteeGovAction{} + case GovActionTypeNewConstitution: + tmpAction = &NewConstitutionGovAction{} + case GovActionTypeInfo: + tmpAction = &InfoGovAction{} + default: + return fmt.Errorf("unknown governance action type: %d", actionType) + } + // Decode action + if _, err := cbor.Decode(data, tmpAction); err != nil { + return err + } + g.Type = uint(actionType) + g.Action = tmpAction + return nil +} + +func (g *GovActionWrapper) MarshalCBOR() ([]byte, error) { + return cbor.Encode(g.Action) +} + +type GovAction interface { + isGovAction() +} + +type ParameterChangeGovAction struct { + cbor.StructAsArray + Type uint + ActionId *GovActionId + ParamUpdate BabbageProtocolParameterUpdate // TODO: use Conway params update type + PolicyHash []byte +} + +func (a ParameterChangeGovAction) isGovAction() {} + +type HardForkInitiationGovAction struct { + cbor.StructAsArray + Type uint + ActionId *GovActionId + ProtocolVersion struct { + cbor.StructAsArray + Major uint + Minor uint + } +} + +func (a HardForkInitiationGovAction) isGovAction() {} + +type TreasuryWithdrawalGovAction struct { + cbor.StructAsArray + Type uint + Withdrawals map[*Address]uint64 + PolicyHash []byte +} + +func (a TreasuryWithdrawalGovAction) isGovAction() {} + +type NoConfidenceGovAction struct { + cbor.StructAsArray + Type uint + ActionId *GovActionId +} + +func (a NoConfidenceGovAction) isGovAction() {} + +type UpdateCommitteeGovAction struct { + cbor.StructAsArray + Type uint + ActionId *GovActionId + Credentials []StakeCredential + CredEpochs map[*StakeCredential]uint + Unknown cbor.Rat +} + +func (a UpdateCommitteeGovAction) isGovAction() {} + +type NewConstitutionGovAction struct { + cbor.StructAsArray + Type uint + ActionId *GovActionId + Constitution struct { + cbor.StructAsArray + Anchor GovAnchor + ScriptHash []byte + } +} + +func (a NewConstitutionGovAction) isGovAction() {} + +type InfoGovAction struct { + cbor.StructAsArray + Type uint +} + +func (a InfoGovAction) isGovAction() {} + type ConwayTransaction struct { cbor.StructAsArray cbor.DecodeStoreCbor @@ -233,6 +373,10 @@ func (t ConwayTransaction) VotingProcedures() VotingProcedures { return t.Body.VotingProcedures() } +func (t ConwayTransaction) ProposalProcedures() []ProposalProcedure { + return t.Body.ProposalProcedures() +} + func (t ConwayTransaction) Metadata() *cbor.Value { return t.TxMetadata } diff --git a/ledger/mary.go b/ledger/mary.go index 6519534e..f6ea4505 100644 --- a/ledger/mary.go +++ b/ledger/mary.go @@ -199,6 +199,10 @@ func (t MaryTransaction) VotingProcedures() VotingProcedures { return t.Body.VotingProcedures() } +func (t MaryTransaction) ProposalProcedures() []ProposalProcedure { + return t.Body.ProposalProcedures() +} + func (t MaryTransaction) Metadata() *cbor.Value { return t.TxMetadata } diff --git a/ledger/shelley.go b/ledger/shelley.go index 7a8e1beb..11af97ae 100644 --- a/ledger/shelley.go +++ b/ledger/shelley.go @@ -249,6 +249,11 @@ func (t *ShelleyTransactionBody) VotingProcedures() VotingProcedures { return nil } +func (t *ShelleyTransactionBody) ProposalProcedures() []ProposalProcedure { + // No proposal procedures in Shelley + return nil +} + func (b *ShelleyTransactionBody) Utxorpc() *utxorpc.Tx { var txi []*utxorpc.TxInput var txo []*utxorpc.TxOutput @@ -411,6 +416,10 @@ func (t ShelleyTransaction) VotingProcedures() VotingProcedures { return t.Body.VotingProcedures() } +func (t ShelleyTransaction) ProposalProcedures() []ProposalProcedure { + return t.Body.ProposalProcedures() +} + func (t ShelleyTransaction) Metadata() *cbor.Value { return t.TxMetadata } diff --git a/ledger/tx.go b/ledger/tx.go index 040dba8c..39c77987 100644 --- a/ledger/tx.go +++ b/ledger/tx.go @@ -47,6 +47,7 @@ type TransactionBody interface { Certificates() []Certificate Withdrawals() map[*Address]uint64 VotingProcedures() VotingProcedures + ProposalProcedures() []ProposalProcedure Utxorpc() *utxorpc.Tx }