Skip to content

Commit aa4acc4

Browse files
author
Jenita
committed
feat(ledger):added ToPlutusData() function to gov proposal related types
Signed-off-by: Jenita <[email protected]>
1 parent 1aace8d commit aa4acc4

File tree

2 files changed

+293
-0
lines changed

2 files changed

+293
-0
lines changed

ledger/common/gov.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ package common
1616

1717
import (
1818
"fmt"
19+
"math/big"
20+
"reflect"
1921

2022
"github.com/blinklabs-io/gouroboros/cbor"
2123
"github.com/blinklabs-io/plutigo/pkg/data"
@@ -108,12 +110,26 @@ type GovAnchor struct {
108110
DataHash [32]byte
109111
}
110112

113+
func (a *GovAnchor) ToPlutusData() data.PlutusData {
114+
return data.NewConstr(0,
115+
data.NewByteString([]byte(a.Url)),
116+
data.NewByteString(a.DataHash[:]),
117+
)
118+
}
119+
111120
type GovActionId struct {
112121
cbor.StructAsArray
113122
TransactionId [32]byte
114123
GovActionIdx uint32
115124
}
116125

126+
func (id *GovActionId) ToPlutusData() data.PlutusData {
127+
return data.NewConstr(0,
128+
data.NewByteString(id.TransactionId[:]),
129+
data.NewInteger(big.NewInt(int64(id.GovActionIdx))),
130+
)
131+
}
132+
117133
type ProposalProcedure struct {
118134
cbor.StructAsArray
119135
Deposit uint64
@@ -122,6 +138,14 @@ type ProposalProcedure struct {
122138
Anchor GovAnchor
123139
}
124140

141+
func (p *ProposalProcedure) ToPlutusData() data.PlutusData {
142+
return data.NewConstr(0,
143+
data.NewInteger(big.NewInt(int64(p.Deposit))),
144+
p.RewardAccount.ToPlutusData(),
145+
p.GovAction.ToPlutusData(),
146+
)
147+
}
148+
125149
const (
126150
GovActionTypeParameterChange = 0
127151
GovActionTypeHardForkInitiation = 1
@@ -137,6 +161,10 @@ type GovActionWrapper struct {
137161
Action GovAction
138162
}
139163

164+
func (g *GovActionWrapper) ToPlutusData() data.PlutusData {
165+
return g.Action.ToPlutusData()
166+
}
167+
140168
func (g *GovActionWrapper) UnmarshalCBOR(data []byte) error {
141169
// Determine action type
142170
actionType, err := cbor.DecodeIdFromList(data)
@@ -178,6 +206,7 @@ func (g *GovActionWrapper) MarshalCBOR() ([]byte, error) {
178206

179207
type GovAction interface {
180208
isGovAction()
209+
ToPlutusData() data.PlutusData
181210
}
182211

183212
type ParameterChangeGovAction struct {
@@ -188,6 +217,14 @@ type ParameterChangeGovAction struct {
188217
PolicyHash []byte
189218
}
190219

220+
func (a *ParameterChangeGovAction) ToPlutusData() data.PlutusData {
221+
return data.NewConstr(0,
222+
a.ActionId.ToPlutusData(),
223+
data.NewByteString(a.ParamUpdate),
224+
data.NewByteString(a.PolicyHash),
225+
)
226+
}
227+
191228
func (a ParameterChangeGovAction) isGovAction() {}
192229

193230
type HardForkInitiationGovAction struct {
@@ -201,6 +238,16 @@ type HardForkInitiationGovAction struct {
201238
}
202239
}
203240

241+
func (a *HardForkInitiationGovAction) ToPlutusData() data.PlutusData {
242+
return data.NewConstr(1,
243+
a.ActionId.ToPlutusData(),
244+
data.NewConstr(0,
245+
data.NewInteger(big.NewInt(int64(a.ProtocolVersion.Major))),
246+
data.NewInteger(big.NewInt(int64(a.ProtocolVersion.Minor))),
247+
),
248+
)
249+
}
250+
204251
func (a HardForkInitiationGovAction) isGovAction() {}
205252

206253
type TreasuryWithdrawalGovAction struct {
@@ -210,6 +257,20 @@ type TreasuryWithdrawalGovAction struct {
210257
PolicyHash []byte
211258
}
212259

260+
func (a *TreasuryWithdrawalGovAction) ToPlutusData() data.PlutusData {
261+
pairs := make([][2]data.PlutusData, 0, len(a.Withdrawals))
262+
for addr, amount := range a.Withdrawals {
263+
pairs = append(pairs, [2]data.PlutusData{
264+
data.NewConstr(0, addr.ToPlutusData()),
265+
data.NewInteger(big.NewInt(int64(amount))),
266+
})
267+
}
268+
return data.NewConstr(2,
269+
data.NewMap(pairs),
270+
data.NewByteString(a.PolicyHash),
271+
)
272+
}
273+
213274
func (a TreasuryWithdrawalGovAction) isGovAction() {}
214275

215276
type NoConfidenceGovAction struct {
@@ -218,6 +279,12 @@ type NoConfidenceGovAction struct {
218279
ActionId *GovActionId
219280
}
220281

282+
func (a *NoConfidenceGovAction) ToPlutusData() data.PlutusData {
283+
return data.NewConstr(3,
284+
a.ActionId.ToPlutusData(),
285+
)
286+
}
287+
221288
func (a NoConfidenceGovAction) isGovAction() {}
222289

223290
type UpdateCommitteeGovAction struct {
@@ -229,6 +296,52 @@ type UpdateCommitteeGovAction struct {
229296
Unknown cbor.Rat
230297
}
231298

299+
func (a *UpdateCommitteeGovAction) ToPlutusData() data.PlutusData {
300+
removedItems := make([]data.PlutusData, 0, len(a.Credentials))
301+
for _, cred := range a.Credentials {
302+
removedItems = append(removedItems, cred.ToPlutusData())
303+
}
304+
305+
addedPairs := make([][2]data.PlutusData, 0, len(a.CredEpochs))
306+
for cred, epoch := range a.CredEpochs {
307+
addedPairs = append(addedPairs, [2]data.PlutusData{
308+
cred.ToPlutusData(),
309+
data.NewInteger(big.NewInt(int64(epoch))),
310+
})
311+
}
312+
313+
// Safe handling of Unknown Rat
314+
var num, den *big.Int
315+
if rat := a.Unknown; rat != (cbor.Rat{}) {
316+
val := reflect.ValueOf(rat)
317+
numField := val.FieldByName("num")
318+
denField := val.FieldByName("den")
319+
320+
if numField.IsValid() && !numField.IsNil() {
321+
num = numField.Interface().(*big.Int)
322+
}
323+
if denField.IsValid() && !denField.IsNil() {
324+
den = denField.Interface().(*big.Int)
325+
}
326+
}
327+
328+
// Default values if still nil
329+
if num == nil {
330+
num = big.NewInt(0)
331+
}
332+
if den == nil {
333+
den = big.NewInt(1)
334+
}
335+
336+
return data.NewConstr(4,
337+
a.ActionId.ToPlutusData(),
338+
data.NewList(removedItems...),
339+
data.NewMap(addedPairs),
340+
data.NewInteger(num),
341+
data.NewInteger(den),
342+
)
343+
}
344+
232345
func (a UpdateCommitteeGovAction) isGovAction() {}
233346

234347
type NewConstitutionGovAction struct {
@@ -242,11 +355,25 @@ type NewConstitutionGovAction struct {
242355
}
243356
}
244357

358+
func (a *NewConstitutionGovAction) ToPlutusData() data.PlutusData {
359+
return data.NewConstr(5,
360+
a.ActionId.ToPlutusData(),
361+
data.NewConstr(0,
362+
a.Constitution.Anchor.ToPlutusData(),
363+
data.NewByteString(a.Constitution.ScriptHash),
364+
),
365+
)
366+
}
367+
245368
func (a NewConstitutionGovAction) isGovAction() {}
246369

247370
type InfoGovAction struct {
248371
cbor.StructAsArray
249372
Type uint
250373
}
251374

375+
func (a *InfoGovAction) ToPlutusData() data.PlutusData {
376+
return data.NewConstr(6)
377+
}
378+
252379
func (a InfoGovAction) isGovAction() {}

ledger/common/gov_test.go

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import (
1818
"reflect"
1919
"testing"
2020

21+
"github.com/blinklabs-io/gouroboros/cbor"
2122
"github.com/blinklabs-io/plutigo/pkg/data"
23+
"github.com/stretchr/testify/assert"
2224
)
2325

2426
// Ttests the ToPlutusData method for Voter types
@@ -177,3 +179,167 @@ func TestVotingProcedureToPlutusData(t *testing.T) {
177179
})
178180
}
179181
}
182+
183+
func TestProposalProcedureToPlutusData(t *testing.T) {
184+
addr := Address{}
185+
action := &InfoGovAction{}
186+
187+
pp := &ProposalProcedure{
188+
Deposit: 1000000,
189+
RewardAccount: addr,
190+
GovAction: GovActionWrapper{Action: action},
191+
}
192+
193+
pd := pp.ToPlutusData()
194+
constr, ok := pd.(*data.Constr)
195+
assert.True(t, ok)
196+
assert.Equal(t, uint(0), constr.Tag)
197+
assert.Len(t, constr.Fields, 3)
198+
}
199+
200+
func TestGovActionIdToPlutusData(t *testing.T) {
201+
txId := [32]byte{1, 2, 3, 4}
202+
govActionId := &GovActionId{
203+
TransactionId: txId,
204+
GovActionIdx: 42,
205+
}
206+
207+
pd := govActionId.ToPlutusData()
208+
constr, ok := pd.(*data.Constr)
209+
assert.True(t, ok)
210+
assert.Equal(t, uint(0), constr.Tag)
211+
assert.Len(t, constr.Fields, 2)
212+
}
213+
214+
func TestParameterChangeGovActionToPlutusData(t *testing.T) {
215+
action := &ParameterChangeGovAction{
216+
ActionId: &GovActionId{},
217+
ParamUpdate: []byte{1, 2, 3},
218+
PolicyHash: []byte{4, 5, 6},
219+
}
220+
221+
pd := action.ToPlutusData()
222+
constr, ok := pd.(*data.Constr)
223+
assert.True(t, ok)
224+
assert.Equal(t, uint(0), constr.Tag)
225+
assert.Len(t, constr.Fields, 3)
226+
}
227+
228+
func TestHardForkInitiationGovActionToPlutusData(t *testing.T) {
229+
action := &HardForkInitiationGovAction{
230+
ActionId: &GovActionId{},
231+
ProtocolVersion: struct {
232+
cbor.StructAsArray
233+
Major uint
234+
Minor uint
235+
}{
236+
Major: 8,
237+
Minor: 0,
238+
},
239+
}
240+
241+
pd := action.ToPlutusData()
242+
constr, ok := pd.(*data.Constr)
243+
assert.True(t, ok)
244+
assert.Equal(t, uint(1), constr.Tag)
245+
assert.Len(t, constr.Fields, 2)
246+
}
247+
248+
func TestTreasuryWithdrawalGovActionToPlutusData(t *testing.T) {
249+
addr := Address{}
250+
withdrawals := map[*Address]uint64{
251+
&addr: 5000000,
252+
}
253+
254+
action := &TreasuryWithdrawalGovAction{
255+
Withdrawals: withdrawals,
256+
PolicyHash: []byte{1, 2, 3},
257+
}
258+
259+
pd := action.ToPlutusData()
260+
constr, ok := pd.(*data.Constr)
261+
assert.True(t, ok)
262+
assert.Equal(t, uint(2), constr.Tag)
263+
assert.Len(t, constr.Fields, 2)
264+
}
265+
266+
func TestNoConfidenceGovActionToPlutusData(t *testing.T) {
267+
action := &NoConfidenceGovAction{
268+
ActionId: &GovActionId{},
269+
}
270+
271+
pd := action.ToPlutusData()
272+
constr, ok := pd.(*data.Constr)
273+
assert.True(t, ok)
274+
assert.Equal(t, uint(3), constr.Tag)
275+
assert.Len(t, constr.Fields, 1)
276+
}
277+
278+
func TestUpdateCommitteeGovActionToPlutusData(t *testing.T) {
279+
cred := Credential{
280+
CredType: CredentialTypeAddrKeyHash,
281+
Credential: NewBlake2b224([]byte("test")),
282+
}
283+
creds := []Credential{cred}
284+
credEpochs := map[*Credential]uint{
285+
&cred: 42,
286+
}
287+
288+
// Test with zero value Rat
289+
t.Run("ZeroValueRat", func(t *testing.T) {
290+
action := &UpdateCommitteeGovAction{
291+
ActionId: &GovActionId{},
292+
Credentials: creds,
293+
CredEpochs: credEpochs,
294+
Unknown: cbor.Rat{}, // Zero value
295+
}
296+
297+
pd := action.ToPlutusData()
298+
assert.NotNil(t, pd)
299+
300+
constr, ok := pd.(*data.Constr)
301+
assert.True(t, ok)
302+
assert.Equal(t, uint(4), constr.Tag)
303+
304+
// Verify default values were used
305+
num, ok := constr.Fields[3].(*data.Integer)
306+
assert.True(t, ok)
307+
assert.Equal(t, int64(0), num.Inner.Int64())
308+
309+
den, ok := constr.Fields[4].(*data.Integer)
310+
assert.True(t, ok)
311+
assert.Equal(t, int64(1), den.Inner.Int64())
312+
})
313+
314+
t.Run("NilCase", func(t *testing.T) {
315+
})
316+
}
317+
318+
func TestNewConstitutionGovActionToPlutusData(t *testing.T) {
319+
action := &NewConstitutionGovAction{
320+
ActionId: &GovActionId{},
321+
Constitution: struct {
322+
cbor.StructAsArray
323+
Anchor GovAnchor
324+
ScriptHash []byte
325+
}{
326+
ScriptHash: []byte{1, 2, 3},
327+
},
328+
}
329+
330+
pd := action.ToPlutusData()
331+
constr, ok := pd.(*data.Constr)
332+
assert.True(t, ok)
333+
assert.Equal(t, uint(5), constr.Tag)
334+
assert.Len(t, constr.Fields, 2)
335+
}
336+
337+
func TestInfoGovActionToPlutusData(t *testing.T) {
338+
action := &InfoGovAction{}
339+
340+
pd := action.ToPlutusData()
341+
constr, ok := pd.(*data.Constr)
342+
assert.True(t, ok)
343+
assert.Equal(t, uint(6), constr.Tag)
344+
assert.Len(t, constr.Fields, 0)
345+
}

0 commit comments

Comments
 (0)