Skip to content

Commit 5ec28f4

Browse files
authored
fix(ledger): use amount for conway per CIP-0094 (#1257)
Signed-off-by: Chris Gianelloni <[email protected]>
1 parent cc7fa2d commit 5ec28f4

File tree

2 files changed

+142
-1
lines changed

2 files changed

+142
-1
lines changed

ledger/conway/rules.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,14 @@ func UtxoValidateValueNotConservedUtxo(
255255
for _, cert := range tx.Certificates() {
256256
switch tmpCert := cert.(type) {
257257
case *common.DeregistrationCertificate:
258-
consumedValue += uint64(tmpPparams.KeyDeposit)
258+
// CIP-0094 deregistration uses Amount field for refund (symmetric with registration deposit)
259+
if tmpCert.Amount <= 0 {
260+
return shelley.InvalidCertificateDepositError{
261+
CertificateType: common.CertificateType(tmpCert.CertType),
262+
Amount: tmpCert.Amount,
263+
}
264+
}
265+
consumedValue += uint64(tmpCert.Amount)
259266
case *common.DeregistrationDrepCertificate:
260267
if tmpCert.Amount <= 0 {
261268
return shelley.InvalidCertificateDepositError{
@@ -265,6 +272,7 @@ func UtxoValidateValueNotConservedUtxo(
265272
}
266273
consumedValue += uint64(tmpCert.Amount)
267274
case *common.StakeDeregistrationCertificate:
275+
// Traditional stake deregistration uses protocol KeyDeposit parameter
268276
consumedValue += uint64(tmpPparams.KeyDeposit)
269277
}
270278
}
@@ -286,6 +294,7 @@ func UtxoValidateValueNotConservedUtxo(
286294
producedValue += uint64(tmpPparams.PoolDeposit)
287295
}
288296
case *common.RegistrationCertificate:
297+
// CIP-0094 registration uses Amount field for deposit
289298
if tmpCert.Amount <= 0 {
290299
return shelley.InvalidCertificateDepositError{
291300
CertificateType: common.CertificateType(tmpCert.CertType),
@@ -302,6 +311,7 @@ func UtxoValidateValueNotConservedUtxo(
302311
}
303312
producedValue += uint64(tmpCert.Amount)
304313
case *common.StakeRegistrationCertificate:
314+
// Traditional stake registration uses protocol KeyDeposit parameter
305315
producedValue += uint64(tmpPparams.KeyDeposit)
306316
case *common.StakeRegistrationDelegationCertificate:
307317
if tmpCert.Amount <= 0 {

ledger/conway/rules_test.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) {
502502
var testInputAmount uint64 = 555666777
503503
var testFee uint64 = 123456
504504
var testStakeDeposit uint64 = 2_000_000
505+
var testDepositAmount uint64 = 1_500_000
505506
testOutputExactAmount := testInputAmount - testFee
506507
testOutputUnderAmount := testOutputExactAmount - 999
507508
testOutputOverAmount := testOutputExactAmount + 999
@@ -662,6 +663,136 @@ func TestUtxoValidateValueNotConservedUtxo(t *testing.T) {
662663
)
663664
},
664665
)
666+
// CIP-0094 Registration certificate with valid deposit
667+
t.Run(
668+
"registration certificate valid deposit",
669+
func(t *testing.T) {
670+
testTx.Body.TxOutputs[0].OutputAmount.Amount = testOutputExactAmount - testDepositAmount // Subtract deposit from output
671+
testTx.Body.TxCertificates = []common.CertificateWrapper{
672+
{
673+
Type: uint(common.CertificateTypeRegistration),
674+
Certificate: &common.RegistrationCertificate{
675+
StakeCredential: common.Credential{},
676+
Amount: int64(testDepositAmount),
677+
},
678+
},
679+
}
680+
err := conway.UtxoValidateValueNotConservedUtxo(
681+
testTx,
682+
testSlot,
683+
testLedgerState,
684+
testProtocolParams,
685+
)
686+
if err != nil {
687+
t.Errorf(
688+
"UtxoValidateValueNotConservedUtxo should succeed with valid registration deposit\n got error: %v",
689+
err,
690+
)
691+
}
692+
},
693+
)
694+
// CIP-0094 Registration certificate with invalid deposit (zero)
695+
t.Run(
696+
"registration certificate invalid deposit zero",
697+
func(t *testing.T) {
698+
testTx.Body.TxOutputs[0].OutputAmount.Amount = testOutputExactAmount
699+
testTx.Body.TxCertificates = []common.CertificateWrapper{
700+
{
701+
Type: uint(common.CertificateTypeRegistration),
702+
Certificate: &common.RegistrationCertificate{
703+
StakeCredential: common.Credential{},
704+
Amount: 0,
705+
},
706+
},
707+
}
708+
err := conway.UtxoValidateValueNotConservedUtxo(
709+
testTx,
710+
testSlot,
711+
testLedgerState,
712+
testProtocolParams,
713+
)
714+
if err == nil {
715+
t.Errorf(
716+
"UtxoValidateValueNotConservedUtxo should fail with zero registration deposit",
717+
)
718+
return
719+
}
720+
testErrType := shelley.InvalidCertificateDepositError{}
721+
assert.IsType(
722+
t,
723+
testErrType,
724+
err,
725+
"did not get expected error type: got %T, wanted %T",
726+
err,
727+
testErrType,
728+
)
729+
},
730+
)
731+
// CIP-0094 Deregistration certificate with valid refund
732+
t.Run(
733+
"deregistration certificate valid refund",
734+
func(t *testing.T) {
735+
testTx.Body.TxOutputs[0].OutputAmount.Amount = testOutputExactAmount + testDepositAmount // Add refund to output
736+
testTx.Body.TxCertificates = []common.CertificateWrapper{
737+
{
738+
Type: uint(common.CertificateTypeDeregistration),
739+
Certificate: &common.DeregistrationCertificate{
740+
StakeCredential: common.Credential{},
741+
Amount: int64(testDepositAmount),
742+
},
743+
},
744+
}
745+
err := conway.UtxoValidateValueNotConservedUtxo(
746+
testTx,
747+
testSlot,
748+
testLedgerState,
749+
testProtocolParams,
750+
)
751+
if err != nil {
752+
t.Errorf(
753+
"UtxoValidateValueNotConservedUtxo should succeed with valid deregistration refund\n got error: %v",
754+
err,
755+
)
756+
}
757+
},
758+
)
759+
// CIP-0094 Deregistration certificate with invalid refund (zero)
760+
t.Run(
761+
"deregistration certificate invalid refund zero",
762+
func(t *testing.T) {
763+
testTx.Body.TxOutputs[0].OutputAmount.Amount = testOutputExactAmount
764+
testTx.Body.TxCertificates = []common.CertificateWrapper{
765+
{
766+
Type: uint(common.CertificateTypeDeregistration),
767+
Certificate: &common.DeregistrationCertificate{
768+
StakeCredential: common.Credential{},
769+
Amount: 0,
770+
},
771+
},
772+
}
773+
err := conway.UtxoValidateValueNotConservedUtxo(
774+
testTx,
775+
testSlot,
776+
testLedgerState,
777+
testProtocolParams,
778+
)
779+
if err == nil {
780+
t.Errorf(
781+
"UtxoValidateValueNotConservedUtxo should fail with zero deregistration refund",
782+
)
783+
return
784+
}
785+
testErrType := shelley.InvalidCertificateDepositError{}
786+
assert.IsType(
787+
t,
788+
testErrType,
789+
err,
790+
"did not get expected error type: got %T, wanted %T",
791+
err,
792+
testErrType,
793+
)
794+
},
795+
)
665796
}
666797

667798
func TestUtxoValidateOutputTooSmallUtxo(t *testing.T) {

0 commit comments

Comments
 (0)