Skip to content

Commit 14df903

Browse files
committed
feat: support for stake withdrawals in script context
* fix stake-only address PlutusData representation * fix pointer address PlutusData representation * add SlotState interface for querying slot-to-time and vice versa * fix script context validity range Signed-off-by: Aurora Gaffney <[email protected]>
1 parent 6343717 commit 14df903

File tree

7 files changed

+162
-36
lines changed

7 files changed

+162
-36
lines changed

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ toolchain go1.24.1
77
require (
88
filippo.io/edwards25519 v1.1.0
99
github.com/blinklabs-io/ouroboros-mock v0.3.8
10-
github.com/blinklabs-io/plutigo v0.0.7
10+
github.com/blinklabs-io/plutigo v0.0.8
1111
github.com/btcsuite/btcd/btcutil v1.1.6
1212
github.com/fxamacker/cbor/v2 v2.9.0
1313
github.com/jinzhu/copier v0.4.0
@@ -21,7 +21,7 @@ require (
2121
github.com/bits-and-blooms/bitset v1.20.0 // indirect
2222
github.com/btcsuite/btcd/btcec/v2 v2.3.5 // indirect
2323
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
24-
github.com/consensys/gnark-crypto v0.18.0 // indirect
24+
github.com/consensys/gnark-crypto v0.19.0 // indirect
2525
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
2626
github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect
2727
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3M
55
github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
66
github.com/blinklabs-io/ouroboros-mock v0.3.8 h1:+DAt2rx0ouZUxee5DBMgZq3I1+ZdxFSHG9g3tYl/FKU=
77
github.com/blinklabs-io/ouroboros-mock v0.3.8/go.mod h1:UwQIf4KqZwO13P9d90fbi3UL/X7JaJfeEbqk+bEeFQA=
8-
github.com/blinklabs-io/plutigo v0.0.7 h1:wgb7v47FggrZEfikolV12WhPsWEXzFyzLtak5IrAOEk=
9-
github.com/blinklabs-io/plutigo v0.0.7/go.mod h1:gxTWAu9n7+4SgQ+zAoO91LYU+5WanUNdRkl9mLdm8f8=
8+
github.com/blinklabs-io/plutigo v0.0.8 h1:p0agbMDZ00skO1yx3Mg0S55phz/mCo8nYuixOaAAGJs=
9+
github.com/blinklabs-io/plutigo v0.0.8/go.mod h1:L639Q8i2cSRuBhjgCHttPR0nnYwwsYVT4Btz7KpQjSw=
1010
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
1111
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
1212
github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A=
@@ -33,8 +33,8 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku
3333
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
3434
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
3535
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
36-
github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0=
37-
github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c=
36+
github.com/consensys/gnark-crypto v0.19.0 h1:zXCqeY2txSaMl6G5wFpZzMWJU9HPNh8qxPnYJ1BL9vA=
37+
github.com/consensys/gnark-crypto v0.19.0/go.mod h1:rT23F0XSZqE0mUA0+pRtnL56IbPxs6gp4CeRsBk4XS0=
3838
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
3939
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4040
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

ledger/common/address.go

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,21 @@ func (a *Address) ToPlutusData() data.PlutusData {
311311
// There is no PlutusData representation for Byron addresses
312312
return nil
313313
}
314+
// Stake-only address
315+
if a.paymentPayload == nil && a.stakingPayload != nil {
316+
switch p := a.stakingPayload.(type) {
317+
case AddressPayloadKeyHash:
318+
return data.NewConstr(
319+
0,
320+
data.NewByteString(p.Hash.Bytes()),
321+
)
322+
case AddressPayloadScriptHash:
323+
return data.NewConstr(
324+
1,
325+
data.NewByteString(p.Hash.Bytes()),
326+
)
327+
}
328+
}
314329
// Build payment part
315330
var paymentPd data.PlutusData
316331
switch p := a.paymentPayload.(type) {
@@ -324,8 +339,6 @@ func (a *Address) ToPlutusData() data.PlutusData {
324339
1,
325340
data.NewByteString(p.Hash[:]),
326341
)
327-
default:
328-
return nil
329342
}
330343
// Build stake part
331344
var stakePd data.PlutusData
@@ -359,15 +372,18 @@ func (a *Address) ToPlutusData() data.PlutusData {
359372
)
360373
case AddressPayloadPointer:
361374
stakePd = data.NewConstr(
362-
1,
363-
data.NewInteger(
364-
new(big.Int).SetUint64(p.Slot),
365-
),
366-
data.NewInteger(
367-
new(big.Int).SetUint64(p.TxIndex),
368-
),
369-
data.NewInteger(
370-
new(big.Int).SetUint64(p.CertIndex),
375+
0,
376+
data.NewConstr(
377+
1,
378+
data.NewInteger(
379+
new(big.Int).SetUint64(p.Slot),
380+
),
381+
data.NewInteger(
382+
new(big.Int).SetUint64(p.TxIndex),
383+
),
384+
data.NewInteger(
385+
new(big.Int).SetUint64(p.CertIndex),
386+
),
371387
),
372388
)
373389
default:

ledger/common/script/context.go

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ type TxInfoV3 struct {
124124
Fee uint64
125125
Mint lcommon.MultiAsset[lcommon.MultiAssetTypeMint]
126126
Certificates []lcommon.Certificate
127-
Withdrawals map[*lcommon.Address]uint64
127+
Withdrawals KeyValuePairs[*lcommon.Address, uint64]
128128
ValidRange TimeRange
129129
Signatories []lcommon.Blake2b224
130130
Redeemers KeyValuePairs[ScriptInfo, Redeemer]
@@ -170,22 +170,32 @@ func (t TxInfoV3) ToPlutusData() data.PlutusData {
170170
}
171171

172172
func NewTxInfoV3FromTransaction(
173+
slotState lcommon.SlotState,
173174
tx lcommon.Transaction,
174175
resolvedInputs []lcommon.Utxo,
175-
) TxInfoV3 {
176+
) (TxInfoV3, error) {
177+
validityRange, err := validityRangeInfo(
178+
slotState,
179+
tx.ValidityIntervalStart(),
180+
tx.TTL(),
181+
)
182+
if err != nil {
183+
return TxInfoV3{}, err
184+
}
176185
assetMint := tx.AssetMint()
177186
if assetMint == nil {
178187
assetMint = &lcommon.MultiAsset[lcommon.MultiAssetTypeMint]{}
179188
}
180189
inputs := sortInputs(tx.Inputs())
190+
withdrawals := withdrawalsInfo(tx.Withdrawals())
181191
redeemers := redeemersInfo(
182192
tx.Witnesses(),
183193
scriptPurposeBuilder(
184194
resolvedInputs,
185195
inputs,
186196
*assetMint,
187197
tx.Certificates(),
188-
tx.Withdrawals(),
198+
withdrawals,
189199
// TODO: proposal procedures
190200
// TODO: votes
191201
),
@@ -197,15 +207,12 @@ func NewTxInfoV3FromTransaction(
197207
sortInputs(tx.ReferenceInputs()),
198208
resolvedInputs,
199209
),
200-
Outputs: collapseOutputs(tx.Produced()),
201-
Fee: tx.Fee(),
202-
Mint: *assetMint,
203-
ValidRange: TimeRange{
204-
tx.TTL(),
205-
tx.ValidityIntervalStart(),
206-
},
210+
Outputs: collapseOutputs(tx.Produced()),
211+
Fee: tx.Fee(),
212+
Mint: *assetMint,
213+
ValidRange: validityRange,
207214
Certificates: tx.Certificates(),
208-
Withdrawals: tx.Withdrawals(),
215+
Withdrawals: withdrawals,
209216
Signatories: signatoriesInfo(tx.RequiredSigners()),
210217
Redeemers: redeemers,
211218
Data: tmpData,
@@ -219,7 +226,7 @@ func NewTxInfoV3FromTransaction(
219226
if amt := tx.Donation(); amt > 0 {
220227
ret.TreasuryDonation.Value = amt
221228
}
222-
return ret
229+
return ret, nil
223230
}
224231

225232
type TimeRange struct {
@@ -336,6 +343,54 @@ func sortedRedeemerKeys(
336343
return ret
337344
}
338345

346+
func validityRangeInfo(
347+
slotState lcommon.SlotState,
348+
startSlot uint64,
349+
endSlot uint64,
350+
) (TimeRange, error) {
351+
var ret TimeRange
352+
if startSlot > 0 {
353+
startTime, err := slotState.SlotToTime(startSlot)
354+
if err != nil {
355+
return ret, err
356+
}
357+
ret.lowerBound = uint64(startTime.UnixMilli()) // nolint:gosec
358+
}
359+
if endSlot > 0 {
360+
endTime, err := slotState.SlotToTime(endSlot)
361+
if err != nil {
362+
return ret, err
363+
}
364+
ret.upperBound = uint64(endTime.UnixMilli()) // nolint:gosec
365+
}
366+
return ret, nil
367+
}
368+
369+
func withdrawalsInfo(
370+
withdrawals map[*lcommon.Address]uint64,
371+
) KeyValuePairs[*lcommon.Address, uint64] {
372+
var ret KeyValuePairs[*lcommon.Address, uint64]
373+
for addr, amt := range withdrawals {
374+
ret = append(
375+
ret,
376+
KeyValuePair[*lcommon.Address, uint64]{
377+
Key: addr,
378+
Value: amt,
379+
},
380+
)
381+
}
382+
// Sort by address bytes
383+
slices.SortFunc(
384+
ret,
385+
func(a, b KeyValuePair[*lcommon.Address, uint64]) int {
386+
aBytes, _ := a.Key.Bytes()
387+
bBytes, _ := b.Key.Bytes()
388+
return bytes.Compare(aBytes, bBytes)
389+
},
390+
)
391+
return ret
392+
}
393+
339394
func dataInfo(
340395
witnessSet lcommon.TransactionWitnessSet,
341396
) KeyValuePairs[lcommon.DatumHash, data.PlutusData] {

ledger/common/script/context_test.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"regexp"
2222
"strings"
2323
"testing"
24+
"time"
2425

2526
"github.com/blinklabs-io/gouroboros/cbor"
2627
"github.com/blinklabs-io/gouroboros/ledger/babbage"
@@ -70,6 +71,7 @@ func formatPlutusData(pd data.PlutusData) string {
7071
}
7172

7273
func buildTxInfoV3(
74+
slotState lcommon.SlotState,
7375
txHex string,
7476
inputsHex string,
7577
inputOutputsHex string,
@@ -116,17 +118,45 @@ func buildTxInfoV3(
116118
)
117119
}
118120
// Build TxInfo
119-
txInfo := NewTxInfoV3FromTransaction(tx, resolvedInputs)
121+
txInfo, err := NewTxInfoV3FromTransaction(slotState, tx, resolvedInputs)
122+
if err != nil {
123+
return nil, err
124+
}
120125
return txInfo, nil
121126
}
122127

128+
type mockSlotState struct {
129+
ZeroTime time.Time
130+
ZeroSlot uint64
131+
SlotLength time.Duration
132+
}
133+
134+
func (m mockSlotState) SlotToTime(slot uint64) (time.Time, error) {
135+
slot -= m.ZeroSlot
136+
ret := m.ZeroTime.Add(time.Duration(slot) * m.SlotLength)
137+
return ret, nil
138+
}
139+
140+
func (m mockSlotState) TimeToSlot(t time.Time) (uint64, error) {
141+
// TODO
142+
return 0, nil
143+
}
144+
145+
var preprodSlotState = mockSlotState{
146+
SlotLength: 1 * time.Second,
147+
// Shelley start
148+
ZeroTime: time.UnixMilli(1596059091000),
149+
ZeroSlot: 4492800,
150+
}
151+
123152
var scriptContextV3TestDefs = []struct {
124153
name string
125154
txHex string
126155
inputsHex string
127156
outputsHex string
128157
redeemerTag common.RedeemerTag
129158
redeemerIndex uint32
159+
slotState common.SlotState
130160
expectedCbor string
131161
}{
132162
{
@@ -195,6 +225,16 @@ var scriptContextV3TestDefs = []struct {
195225
redeemerIndex: 20,
196226
expectedCbor: "d8799fd8799f9fd8799fd8799f5820000000000000000000000000000000000000000000000000000000000000000000ffd8799fd8799fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a80ffa140a1401a000f4240d87980d87a80ffffff8080182aa09fd8799fd87a9f581c22222222222222222222222222222222222222222222222222222222ffd87a80ffd8799fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a80ffd87a9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a80ffd905009f581c1111111111111111111111111111111111111111111111111111111158209999999999999999999999999999999999999999999999999999999999999999ffd905019f581c11111111111111111111111111111111111111111111111111111111190539ffd8799fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a80ffd87a9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a80ffd87b9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a9fd8799fd8799f581c00000000000000000000000000000000000000000000000000000000ffffffffd87b9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a9fd8799fd87a9f581c00000000000000000000000000000000000000000000000000000000ffffffffd87b9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a9fd87a80ffffd87b9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a9fd87b80ffffd87b9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87b9f581c11111111111111111111111111111111111111111111111111111111d87b80ffffd87c9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd8799f581c11111111111111111111111111111111111111111111111111111111ff1a002dc6c0ffd87c9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87a9fd87b80ff1a002dc6c0ffd87c9fd8799f581c00000000000000000000000000000000000000000000000000000000ffd87b9f581c11111111111111111111111111111111111111111111111111111111d87b80ff1a002dc6c0ffd905029fd8799f581c00000000000000000000000000000000000000000000000000000000ffd8799f581c22222222222222222222222222222222222222222222222222222222ffffd905039fd8799f581c00000000000000000000000000000000000000000000000000000000ffffd87d9fd8799f581c00000000000000000000000000000000000000000000000000000000ff1a002dc6c0ffd87f9fd8799f581c00000000000000000000000000000000000000000000000000000000ff1a002dc6c0ffd87e9fd8799f581c00000000000000000000000000000000000000000000000000000000ffffd87b9fd87a9f581c9b24324046544393443e1fb35c8b72c3c39e18a516a95df5f6654101ffd8799f581c11111111111111111111111111111111111111111111111111111111ffffffa0d8799fd8799fd87980d87a80ffd8799fd87b80d87a80ffff80a1d87c9f14d87b9fd87a9f581c9b24324046544393443e1fb35c8b72c3c39e18a516a95df5f6654101ffd8799f581c11111111111111111111111111111111111111111111111111111111ffffffd87980a0582080bf68ced2c50b8734fc8cebd0a049e16e53d2fe5ec7e42822f07c263ced98aba080d8799f1a00989680ffd8799f0effffd87980d87c9f14d87b9fd87a9f581c9b24324046544393443e1fb35c8b72c3c39e18a516a95df5f6654101ffd8799f581c11111111111111111111111111111111111111111111111111111111ffffffff",
197227
},
228+
{
229+
name: "Withdraw",
230+
txHex: "84a700818258200000000000000000000000000000000000000000000000000000000000000000000183a2005839200000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111011a000f4240a200582340000000000000000000000000000000000000000000000000000000008198bd431b03011a000f4240a200582350111111111111111111111111111111111111111111111111111111118198bd431b03011a000f424002182a031a00448e0105a1581df004036eecadc2f19e95f831b4bc08919cde1d1088d74602bd3dcd78a2000e81581c000000000000000000000000000000000000000000000000000000001601a10582840000d87a81d87980821a000f42401a05f5e100840300d87980821a000f42401a05f5e100f5f6",
231+
inputsHex: "81825820000000000000000000000000000000000000000000000000000000000000000000",
232+
outputsHex: "81a40058393004036eecadc2f19e95f831b4bc08919cde1d1088d74602bd3dcd78a204036eecadc2f19e95f831b4bc08919cde1d1088d74602bd3dcd78a2011a000f4240028201d81843d8798003d818590221820359021c5902190101003232323232323232322232533333300c00215323330073001300937540062a660109211c52756e6e696e672032206172672076616c696461746f72206d696e740013533333300d004153330073001300937540082a66601660146ea8010494ccc021288a4c2a660129211856616c696461746f722072657475726e65642066616c7365001365600600600600600600600315330084911d52756e6e696e672033206172672076616c696461746f72207370656e640013533333300d004153330073001300937540082a66601660146ea8010494cccccc03800454ccc020c008c028dd50008a99980618059baa0011253330094a22930a998052491856616c696461746f722072657475726e65642066616c73650013656006006006006006006006006006006006006300c300a37540066e1d2000153300700116153300700116153300700116153300700116490191496e636f72726563742072656465656d6572207479706520666f722076616c696461746f72207370656e642e0a2020202020202020202020202020202020202020446f75626c6520636865636b20796f7520686176652077726170706564207468652072656465656d657220747970652061732073706563696669656420696e20796f757220706c757475732e6a736f6e0015330034910b5f746d70313a20566f6964001615330024910b5f746d70303a20566f696400165734ae7155ceaab9e5573eae855d21",
233+
redeemerTag: common.RedeemerTagReward,
234+
redeemerIndex: 0,
235+
slotState: preprodSlotState,
236+
expectedCbor: "d8799fd8799f9fd8799fd8799f5820000000000000000000000000000000000000000000000000000000000000000000ffd8799fd8799fd87a9f581c04036eecadc2f19e95f831b4bc08919cde1d1088d74602bd3dcd78a2ffd8799fd8799fd87a9f581c04036eecadc2f19e95f831b4bc08919cde1d1088d74602bd3dcd78a2ffffffffa140a1401a000f4240d87b9fd87980ffd8799f581c04036eecadc2f19e95f831b4bc08919cde1d1088d74602bd3dcd78a2ffffffff809fd8799fd8799fd8799f581c00000000000000000000000000000000000000000000000000000000ffd8799fd8799fd87a9f581c11111111111111111111111111111111111111111111111111111111ffffffffa140a1401a000f4240d87980d87a80ffd8799fd8799fd8799f581c00000000000000000000000000000000000000000000000000000000ffd8799fd87a9f1a00261ec3181b03ffffffa140a1401a000f4240d87980d87a80ffd8799fd8799fd87a9f581c11111111111111111111111111111111111111111111111111111111ffd8799fd87a9f1a00261ec3181b03ffffffa140a1401a000f4240d87980d87a80ffff182aa080a1d87a9f581c04036eecadc2f19e95f831b4bc08919cde1d1088d74602bd3dcd78a2ff00d8799fd8799fd87980d87a80ffd8799fd87a9f1b000001739c890420ffd87980ffff9f581c00000000000000000000000000000000000000000000000000000000ffa2d87a9fd8799f5820000000000000000000000000000000000000000000000000000000000000000000ffffd87a81d87980d87b9fd87a9f581c04036eecadc2f19e95f831b4bc08919cde1d1088d74602bd3dcd78a2ffffd87980a0582040bee3b25a585a854fe73f3448a6f6b417fe669c813a1881e665971f34a9e984a080d87a80d8799f01ffffd87980d87b9fd87a9f581c04036eecadc2f19e95f831b4bc08919cde1d1088d74602bd3dcd78a2ffffff",
237+
},
198238
}
199239

200240
func TestScriptContextV3(t *testing.T) {
@@ -203,6 +243,7 @@ func TestScriptContextV3(t *testing.T) {
203243
testDef.name,
204244
func(t *testing.T) {
205245
txInfo, err := buildTxInfoV3(
246+
testDef.slotState,
206247
testDef.txHex,
207248
testDef.inputsHex,
208249
testDef.outputsHex,

ledger/common/script/purpose.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,14 @@ type ScriptInfoRewarding struct {
8282
func (ScriptInfoRewarding) isScriptInfo() {}
8383

8484
func (s ScriptInfoRewarding) ScriptHash() lcommon.ScriptHash {
85-
// TODO
86-
return lcommon.ScriptHash{}
85+
return lcommon.ScriptHash(s.StakeCredential.Credential)
8786
}
8887

8988
func (s ScriptInfoRewarding) ToPlutusData() data.PlutusData {
90-
// TODO
91-
return nil
89+
return data.NewConstr(
90+
2,
91+
s.StakeCredential.ToPlutusData(),
92+
)
9293
}
9394

9495
type ScriptInfoCertifying struct {
@@ -187,7 +188,7 @@ func scriptPurposeBuilder(
187188
inputs []lcommon.TransactionInput,
188189
mint lcommon.MultiAsset[lcommon.MultiAssetTypeMint],
189190
certificates []lcommon.Certificate,
190-
withdrawals map[*lcommon.Address]uint64,
191+
withdrawals KeyValuePairs[*lcommon.Address, uint64],
191192
// TODO: proposal procedures
192193
// TODO: votes
193194
) toScriptPurposeFunc {
@@ -228,7 +229,12 @@ func scriptPurposeBuilder(
228229
Certificate: certificates[redeemerKey.Index],
229230
}
230231
case lcommon.RedeemerTagReward:
231-
return nil
232+
return ScriptInfoRewarding{
233+
StakeCredential: lcommon.Credential{
234+
CredType: lcommon.CredentialTypeScriptHash,
235+
Credential: withdrawals[redeemerKey.Index].Key.StakeKeyHash(),
236+
},
237+
}
232238
case lcommon.RedeemerTagVoting:
233239
return nil
234240
case lcommon.RedeemerTagProposing:

ledger/common/state.go

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

1717
import (
18+
"time"
19+
1820
pcommon "github.com/blinklabs-io/gouroboros/protocol/common"
1921
)
2022

@@ -40,3 +42,9 @@ type LedgerState interface {
4042
type TipState interface {
4143
Tip() (pcommon.Tip, error)
4244
}
45+
46+
// SlotState defines the interface for querying slots
47+
type SlotState interface {
48+
SlotToTime(uint64) (time.Time, error)
49+
TimeToSlot(time.Time) (uint64, error)
50+
}

0 commit comments

Comments
 (0)