Skip to content

Commit 8d1aaa4

Browse files
committed
feat: implement unified certificate persistence system
- Add SetCertificate method handling all Cardano certificate types - Switch interface from slot to ocommon.Point for consistency - Add comprehensive test suite with 19 test cases - Remove deprecated certificate setter methods - Include certificate mapping model and migration updates Signed-off-by: GitHub Copilot <[email protected]> Signed-off-by: Chris Gianelloni <[email protected]>
1 parent f666199 commit 8d1aaa4

40 files changed

+2858
-1362
lines changed

database/account.go

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

1717
import (
1818
"github.com/blinklabs-io/dingo/database/models"
19-
"github.com/blinklabs-io/dingo/database/types"
20-
lcommon "github.com/blinklabs-io/gouroboros/ledger/common"
2119
)
2220

2321
// GetAccount returns an account by staking key
@@ -38,143 +36,3 @@ func (d *Database) GetAccount(
3836
}
3937
return account, nil
4038
}
41-
42-
// SetDeregistration saves a deregistration certificate
43-
func (d *Database) SetDeregistration(
44-
cert *lcommon.DeregistrationCertificate,
45-
slot uint64,
46-
txn *Txn,
47-
) error {
48-
return d.metadata.SetDeregistration(
49-
cert,
50-
slot,
51-
txn.Metadata(),
52-
)
53-
}
54-
55-
// SetRegistration saves a registration certificate
56-
func (d *Database) SetRegistration(
57-
cert *lcommon.RegistrationCertificate,
58-
slot uint64,
59-
deposit uint64,
60-
txn *Txn,
61-
) error {
62-
return d.metadata.SetRegistration(
63-
cert,
64-
slot,
65-
types.Uint64(deposit),
66-
txn.Metadata(),
67-
)
68-
}
69-
70-
// SetStakeDelegation saves a stake delegation certificate
71-
func (d *Database) SetStakeDelegation(
72-
cert *lcommon.StakeDelegationCertificate,
73-
slot uint64,
74-
txn *Txn,
75-
) error {
76-
return d.metadata.SetStakeDelegation(
77-
cert,
78-
slot,
79-
txn.Metadata(),
80-
)
81-
}
82-
83-
// SetStakeDeregistration saves a stake deregistration certificate
84-
func (d *Database) SetStakeDeregistration(
85-
cert *lcommon.StakeDeregistrationCertificate,
86-
slot uint64,
87-
txn *Txn,
88-
) error {
89-
return d.metadata.SetStakeDeregistration(
90-
cert,
91-
slot,
92-
txn.Metadata(),
93-
)
94-
}
95-
96-
// SetStakeRegistration saves a stake registration certificate
97-
func (d *Database) SetStakeRegistration(
98-
cert *lcommon.StakeRegistrationCertificate,
99-
slot uint64,
100-
deposit uint64,
101-
txn *Txn,
102-
) error {
103-
return d.metadata.SetStakeRegistration(
104-
cert,
105-
slot,
106-
types.Uint64(deposit),
107-
txn.Metadata(),
108-
)
109-
}
110-
111-
// SetStakeRegistrationDelegation saves a stake registration delegation certificate
112-
func (d *Database) SetStakeRegistrationDelegation(
113-
cert *lcommon.StakeRegistrationDelegationCertificate,
114-
slot uint64,
115-
deposit uint64,
116-
txn *Txn,
117-
) error {
118-
return d.metadata.SetStakeRegistrationDelegation(
119-
cert,
120-
slot,
121-
types.Uint64(deposit),
122-
txn.Metadata(),
123-
)
124-
}
125-
126-
// SetStakeVoteDelegation saves a stake vote delegation certificate
127-
func (d *Database) SetStakeVoteDelegation(
128-
cert *lcommon.StakeVoteDelegationCertificate,
129-
slot uint64,
130-
txn *Txn,
131-
) error {
132-
return d.metadata.SetStakeVoteDelegation(
133-
cert,
134-
slot,
135-
txn.Metadata(),
136-
)
137-
}
138-
139-
// SetStakeVoteRegistrationDelegation saves a stake vote registration delegation certificate
140-
func (d *Database) SetStakeVoteRegistrationDelegation(
141-
cert *lcommon.StakeVoteRegistrationDelegationCertificate,
142-
slot uint64,
143-
deposit uint64,
144-
txn *Txn,
145-
) error {
146-
return d.metadata.SetStakeVoteRegistrationDelegation(
147-
cert,
148-
slot,
149-
types.Uint64(deposit),
150-
txn.Metadata(),
151-
)
152-
}
153-
154-
// SetVoteDelegation saves a vote delegation certificate
155-
func (d *Database) SetVoteDelegation(
156-
cert *lcommon.VoteDelegationCertificate,
157-
slot uint64,
158-
txn *Txn,
159-
) error {
160-
return d.metadata.SetVoteDelegation(
161-
cert,
162-
slot,
163-
txn.Metadata(),
164-
)
165-
}
166-
167-
// SetVoteRegistrationDelegation saves a vote registration delegation certificate
168-
func (d *Database) SetVoteRegistrationDelegation(
169-
cert *lcommon.VoteRegistrationDelegationCertificate,
170-
slot uint64,
171-
deposit uint64,
172-
txn *Txn,
173-
) error {
174-
return d.metadata.SetVoteRegistrationDelegation(
175-
cert,
176-
slot,
177-
types.Uint64(deposit),
178-
txn.Metadata(),
179-
)
180-
}

database/certs.go renamed to database/certificate.go

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,46 +15,25 @@
1515
package database
1616

1717
import (
18-
"github.com/blinklabs-io/dingo/database/types"
1918
lcommon "github.com/blinklabs-io/gouroboros/ledger/common"
2019
)
2120

22-
// GetPoolRegistrations returns a list of pool registration certificates
21+
// Certificate persistence is handled by SetTransaction.
22+
// The ledger layer calculates deposits and calls SetTransaction
23+
// to persist transactions and certificates together in a single operation.
24+
25+
// GetPoolRegistrations returns pool registration certificates for the given pool key hash
2326
func (d *Database) GetPoolRegistrations(
2427
poolKeyHash lcommon.PoolKeyHash,
2528
txn *Txn,
2629
) ([]lcommon.PoolRegistrationCertificate, error) {
2730
return d.metadata.GetPoolRegistrations(poolKeyHash, txn.Metadata())
2831
}
2932

30-
// GetStakeRegistrations returns a list of stake registration certificates
33+
// GetStakeRegistrations returns stake registration certificates for the given staking key
3134
func (d *Database) GetStakeRegistrations(
3235
stakingKey []byte,
3336
txn *Txn,
3437
) ([]lcommon.StakeRegistrationCertificate, error) {
3538
return d.metadata.GetStakeRegistrations(stakingKey, txn.Metadata())
3639
}
37-
38-
// SetPoolRegistration saves a pool registration certificate
39-
func (d *Database) SetPoolRegistration(
40-
cert *lcommon.PoolRegistrationCertificate,
41-
slot uint64,
42-
deposit uint64,
43-
txn *Txn,
44-
) error {
45-
return d.metadata.SetPoolRegistration(
46-
cert,
47-
slot,
48-
types.Uint64(deposit),
49-
txn.Metadata(),
50-
)
51-
}
52-
53-
// SetPoolRetirement saves a pool retirement certificate
54-
func (d *Database) SetPoolRetirement(
55-
cert *lcommon.PoolRetirementCertificate,
56-
slot uint64,
57-
txn *Txn,
58-
) error {
59-
return d.metadata.SetPoolRetirement(cert, slot, txn.Metadata())
60-
}

database/drep.go

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -13,51 +13,3 @@
1313
// limitations under the License.
1414

1515
package database
16-
17-
import (
18-
"github.com/blinklabs-io/dingo/database/types"
19-
lcommon "github.com/blinklabs-io/gouroboros/ledger/common"
20-
)
21-
22-
// SetRegistrationDrep saves a registration drep certificate
23-
func (d *Database) SetRegistrationDrep(
24-
cert *lcommon.RegistrationDrepCertificate,
25-
slot uint64,
26-
deposit uint64,
27-
txn *Txn,
28-
) error {
29-
return d.metadata.SetRegistrationDrep(
30-
cert,
31-
slot,
32-
types.Uint64(deposit),
33-
txn.Metadata(),
34-
)
35-
}
36-
37-
// SetDeregistrationDrep saves a deregistration drep certificate
38-
func (d *Database) SetDeregistrationDrep(
39-
cert *lcommon.DeregistrationDrepCertificate,
40-
slot uint64,
41-
deposit uint64,
42-
txn *Txn,
43-
) error {
44-
return d.metadata.SetDeregistrationDrep(
45-
cert,
46-
slot,
47-
types.Uint64(deposit),
48-
txn.Metadata(),
49-
)
50-
}
51-
52-
// SetUpdateDrep saves an update drep certificate
53-
func (d *Database) SetUpdateDrep(
54-
cert *lcommon.UpdateDrepCertificate,
55-
slot uint64,
56-
txn *Txn,
57-
) error {
58-
return d.metadata.SetUpdateDrep(
59-
cert,
60-
slot,
61-
txn.Metadata(),
62-
)
63-
}

database/models/account.go

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ import (
2525
var ErrAccountNotFound = errors.New("account not found")
2626

2727
type Account struct {
28-
StakingKey []byte `gorm:"uniqueIndex"`
28+
StakingKey []byte `gorm:"index"`
2929
Pool []byte `gorm:"index"`
3030
Drep []byte `gorm:"index"`
3131
ID uint `gorm:"primarykey"`
32-
AddedSlot uint64
33-
CertificateID uint `gorm:"index"`
34-
Active bool `gorm:"default:true"`
32+
AddedSlot uint64 `gorm:"index"`
33+
CertificateID uint `gorm:"index"`
34+
Active bool `gorm:"index;default:true"`
3535
}
3636

3737
func (a *Account) TableName() string {
@@ -57,10 +57,18 @@ func (a *Account) String() (string, error) {
5757
return encoded, nil
5858
}
5959

60+
// Certificate models constraint strategy:
61+
// - Deregistration, StakeDeregistration, and StakeRegistration use composite unique constraints on (StakingKey, CertificateID)
62+
// to prevent duplicate certificates for the same staking key and certificate ID.
63+
// - Other certificate models (Registration, StakeDelegation, etc.) use simple indexes
64+
// without uniqueness constraints, allowing multiple entries for the same staking key across different certificates.
65+
// This design ensures that deregistration and stake registration certificates are processed only once,
66+
// while other certificate types can be handled multiple times if needed (e.g., for historical tracking or retries).
67+
6068
type Deregistration struct {
61-
StakingKey []byte `gorm:"index"`
69+
StakingKey []byte `gorm:"index;uniqueIndex:uniq_deregistration_cert"`
6270
ID uint `gorm:"primarykey"`
63-
CertificateID uint `gorm:"index"`
71+
CertificateID uint `gorm:"uniqueIndex:uniq_deregistration_cert"`
6472
AddedSlot uint64
6573
Amount types.Uint64
6674
}
@@ -94,8 +102,8 @@ func (StakeDelegation) TableName() string {
94102
}
95103

96104
type StakeDeregistration struct {
97-
StakingKey []byte `gorm:"index"`
98-
CertificateID uint `gorm:"index"`
105+
StakingKey []byte `gorm:"index;uniqueIndex:uniq_stake_deregistration_cert"`
106+
CertificateID uint `gorm:"uniqueIndex:uniq_stake_deregistration_cert"`
99107
ID uint `gorm:"primarykey"`
100108
AddedSlot uint64
101109
}
@@ -105,8 +113,8 @@ func (StakeDeregistration) TableName() string {
105113
}
106114

107115
type StakeRegistration struct {
108-
StakingKey []byte `gorm:"index"`
109-
CertificateID uint `gorm:"index"`
116+
StakingKey []byte `gorm:"index;uniqueIndex:uniq_stake_registration_cert"`
117+
CertificateID uint `gorm:"uniqueIndex:uniq_stake_registration_cert"`
110118
ID uint `gorm:"primarykey"`
111119
AddedSlot uint64
112120
DepositAmount types.Uint64

database/models/account_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ import (
2626
func TestAccount_String(t *testing.T) {
2727
tests := []struct {
2828
name string
29+
wantErrMsg string
30+
expectedHRP string
2931
stakingKey []byte
3032
wantErr bool
31-
wantErrMsg string
3233
validateAddr bool
33-
expectedHRP string
3434
}{
3535
{
3636
name: "valid staking key - 28 bytes",

database/models/asset.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func ConvertMultiAssetToModels(
7070
NameHex: []byte(hex.EncodeToString(assetNameBytes)),
7171
PolicyId: policyIdBytes,
7272
Fingerprint: []byte(fingerprint.String()),
73-
Amount: types.Uint64(amount),
73+
Amount: types.Uint64{Val: amount},
7474
}
7575
assets = append(assets, asset)
7676
}

database/models/auth_committee_hot.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,16 @@
1414

1515
package models
1616

17+
import (
18+
"github.com/blinklabs-io/dingo/database/types"
19+
)
20+
1721
type AuthCommitteeHot struct {
18-
ColdCredential []byte `gorm:"index"`
19-
HostCredential []byte `gorm:"index"`
20-
ID uint `gorm:"primarykey"`
21-
AddedSlot uint64
22+
ColdCredential []byte `gorm:"unique"`
23+
HostCredential []byte `gorm:"index"`
24+
ID uint `gorm:"primarykey"`
25+
CertificateID uint `gorm:"uniqueIndex:uniq_auth_committee_hot_cert"`
26+
AddedSlot types.Uint64 `gorm:"index"`
2227
}
2328

2429
func (AuthCommitteeHot) TableName() string {

0 commit comments

Comments
 (0)