Skip to content

Commit 7267538

Browse files
authored
fix(ledger): script refs are inert unless triggered (#1601)
Signed-off-by: Chris Gianelloni <wolf31o2@blinklabs.io>
1 parent fa79e51 commit 7267538

File tree

4 files changed

+52
-27
lines changed

4 files changed

+52
-27
lines changed

ledger/alonzo/rules.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -804,22 +804,19 @@ func UtxoValidateScriptDataHash(
804804
usedVersions[0] = struct{}{}
805805
}
806806

807-
hasPlutusScripts := len(usedVersions) > 0
808807
declaredHash := tx.ScriptDataHash()
809808

810-
// If no Plutus scripts and no redeemers/datums, ScriptDataHash should be absent
811-
if !hasPlutusScripts && !hasRedeemers && !hasDatums {
809+
// ScriptDataHash is required only when the transaction has redeemers or
810+
// witness datums, indicating actual script execution.
811+
if !hasRedeemers && !hasDatums {
812812
if declaredHash != nil {
813813
return common.ExtraneousScriptDataHashError{Provided: *declaredHash}
814814
}
815815
return nil
816816
}
817817

818-
// If there are Plutus scripts/redeemers/datums, ScriptDataHash is required
819-
if hasPlutusScripts || hasRedeemers || hasDatums {
820-
if declaredHash == nil {
821-
return common.MissingScriptDataHashError{}
822-
}
818+
if declaredHash == nil {
819+
return common.MissingScriptDataHashError{}
823820
}
824821

825822
// Verify cost models are present for all used Plutus versions

ledger/babbage/rules.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,8 @@ func UtxoValidateScriptDataHash(
11091109
}
11101110
}
11111111

1112-
// Check scripts in regular inputs
1112+
// Check reference scripts on regular inputs.
1113+
// These may provide reference scripts for minting, spending, etc.
11131114
for _, input := range tmpTx.Inputs() {
11141115
utxo, err := ls.UtxoById(input)
11151116
if err != nil {
@@ -1130,22 +1131,21 @@ func UtxoValidateScriptDataHash(
11301131
}
11311132
}
11321133

1133-
hasPlutusScripts := len(usedVersions) > 0
11341134
declaredHash := tx.ScriptDataHash()
11351135

1136-
// If no Plutus scripts and no redeemers/datums, ScriptDataHash should be absent
1137-
if !hasPlutusScripts && !hasRedeemers && !hasDatums {
1136+
// ScriptDataHash is required only when the transaction has redeemers or
1137+
// witness datums, indicating actual script execution. The mere presence
1138+
// of ScriptRefs in consumed/referenced UTxOs does NOT require a hash —
1139+
// they are inert data unless matched by a redeemer.
1140+
if !hasRedeemers && !hasDatums {
11381141
if declaredHash != nil {
11391142
return common.ExtraneousScriptDataHashError{Provided: *declaredHash}
11401143
}
11411144
return nil
11421145
}
11431146

1144-
// If there are Plutus scripts/redeemers/datums, ScriptDataHash is required
1145-
if hasPlutusScripts || hasRedeemers || hasDatums {
1146-
if declaredHash == nil {
1147-
return common.MissingScriptDataHashError{}
1148-
}
1147+
if declaredHash == nil {
1148+
return common.MissingScriptDataHashError{}
11491149
}
11501150

11511151
// Verify cost models are present for all used Plutus versions

ledger/common/errors.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,31 @@ func (e MissingCostModelError) Error() string {
3535
return fmt.Sprintf("missing cost model for Plutus v%d", e.Version+1)
3636
}
3737

38+
// InputResolutionError indicates a failure to resolve a regular input UTxO
39+
type InputResolutionError struct {
40+
Input TransactionInput
41+
Err error
42+
}
43+
44+
func (e InputResolutionError) Error() string {
45+
return fmt.Sprintf(
46+
"failed to resolve input %s: %v",
47+
e.Input.String(),
48+
e.Err,
49+
)
50+
}
51+
52+
func (e InputResolutionError) Unwrap() error { return e.Err }
53+
54+
// Sentinel error for input resolution failures so callers can use errors.Is
55+
var ErrInputResolution = errors.New(
56+
"input resolution failed",
57+
)
58+
59+
func (InputResolutionError) Is(target error) bool {
60+
return target == ErrInputResolution
61+
}
62+
3863
// ReferenceInputResolutionError indicates a failure to resolve a reference input UTxO
3964
type ReferenceInputResolutionError struct {
4065
Input TransactionInput

ledger/conway/rules.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,8 @@ func UtxoValidateScriptDataHash(
722722
}
723723
}
724724

725-
// Check scripts in regular inputs
725+
// Check reference scripts on regular inputs.
726+
// These may provide reference scripts for minting, spending, etc.
726727
for _, input := range tmpTx.Inputs() {
727728
utxo, err := ls.UtxoById(input)
728729
if err != nil {
@@ -745,22 +746,21 @@ func UtxoValidateScriptDataHash(
745746
}
746747
}
747748

748-
hasPlutusScripts := len(usedVersions) > 0
749749
declaredHash := tx.ScriptDataHash()
750750

751-
// If no Plutus scripts and no redeemers/datums, ScriptDataHash should be absent
752-
if !hasPlutusScripts && !hasRedeemers && !hasDatums {
751+
// ScriptDataHash is required only when the transaction has redeemers or
752+
// witness datums, indicating actual script execution. The mere presence
753+
// of ScriptRefs in consumed/referenced UTxOs does NOT require a hash —
754+
// they are inert data unless matched by a redeemer.
755+
if !hasRedeemers && !hasDatums {
753756
if declaredHash != nil {
754757
return common.ExtraneousScriptDataHashError{Provided: *declaredHash}
755758
}
756759
return nil
757760
}
758761

759-
// If there are Plutus scripts/redeemers/datums, ScriptDataHash is required
760-
if hasPlutusScripts || hasRedeemers || hasDatums {
761-
if declaredHash == nil {
762-
return common.MissingScriptDataHashError{}
763-
}
762+
if declaredHash == nil {
763+
return common.MissingScriptDataHashError{}
764764
}
765765

766766
// Verify cost models are present for all used Plutus versions
@@ -1903,7 +1903,10 @@ func UtxoValidatePlutusScripts(
19031903
for _, input := range tx.Inputs() {
19041904
utxo, err := ls.UtxoById(input)
19051905
if err != nil {
1906-
continue
1906+
return common.InputResolutionError{
1907+
Input: input,
1908+
Err: err,
1909+
}
19071910
}
19081911
resolvedInputs = append(resolvedInputs, utxo)
19091912
resolvedInputsMap[input.String()] = utxo

0 commit comments

Comments
 (0)