From 648aebc2f7216507b34d75d1ec214aaf45ec969d Mon Sep 17 00:00:00 2001 From: Luca Moser Date: Wed, 24 Aug 2022 13:25:10 +0200 Subject: [PATCH 1/8] adds alias needs to state transition if it is refed by an alias unlock --- transaction.go | 23 +++++++++++++++++++++++ transaction_test.go | 17 +++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/transaction.go b/transaction.go index 6fb98f7eb..858860431 100644 --- a/transaction.go +++ b/transaction.go @@ -482,7 +482,30 @@ func TxSemanticInputUnlocks() TxSemanticValidationFunc { } svCtx.WorkingSet.UnlockedIdents.AddUnlockedChain(chainID.ToAddress(), uint16(inputIndex)) } + } + + // check whether any alias output which is referenced is not doing a state transition + for _, v := range svCtx.WorkingSet.UnlockedIdents { + if len(v.ReferencedBy) == 0 { + continue + } + input := svCtx.WorkingSet.Inputs[v.UnlockedAt] + current, ok := input.(*AliasOutput) + if !ok { + continue + } + + // there can be multiple entries given a chain output + aliasAddr, ok := v.Ident.(*AliasAddress) + if !ok { + continue + } + + next, hasNextState := svCtx.WorkingSet.OutChains[aliasAddr.Chain()] + if !hasNextState || (current.StateIndex+1 != next.(*AliasOutput).StateIndex) { + return fmt.Errorf("%w: input alias output at %d is referenced by %v, but the alias output is not state transitioning", ErrInvalidInputUnlock, v.UnlockedAt, v.ReferencedBy) + } } return nil diff --git a/transaction_test.go b/transaction_test.go index 658bcb962..0718bd8c2 100644 --- a/transaction_test.go +++ b/transaction_test.go @@ -206,7 +206,7 @@ func TestCirculatingSupplyMelting(t *testing.T) { Amount: OneMi, NativeTokens: nil, AliasID: aliasIdent1.AliasID(), - StateIndex: 1, + StateIndex: 2, StateMetadata: nil, FoundryCounter: 1, Conditions: iotago.UnlockConditions{ @@ -836,7 +836,20 @@ func TestTxSemanticInputUnlocks(t *testing.T) { }, } - essence := &iotago.TransactionEssence{Inputs: inputIDs.UTXOInputs()} + essence := &iotago.TransactionEssence{ + Inputs: inputIDs.UTXOInputs(), + Outputs: iotago.Outputs{ + &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasIdent1.AliasID(), + StateIndex: 1, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: ident1}, + &iotago.GovernorAddressUnlockCondition{Address: ident1}, + }, + }, + }, + } sigs, err := essence.Sign(inputIDs.OrderedSet(inputs).MustCommitment(), ident1AddrKeys, ident2AddrKeys) require.NoError(t, err) From 7ea15e536993f3909167f2cdb5d190ea1fdf743f Mon Sep 17 00:00:00 2001 From: Luca Moser Date: Wed, 24 Aug 2022 13:31:18 +0200 Subject: [PATCH 2/8] adds test --- transaction_test.go | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/transaction_test.go b/transaction_test.go index 0718bd8c2..bf89a5938 100644 --- a/transaction_test.go +++ b/transaction_test.go @@ -1168,6 +1168,63 @@ func TestTxSemanticInputUnlocks(t *testing.T) { wantErr: iotago.ErrInvalidInputUnlock, } }(), + func() test { + _, ident1, _ := tpkg.RandEd25519Identity() + _, ident2, ident2AddressKeys := tpkg.RandEd25519Identity() + inputIDs := tpkg.RandOutputIDs(2) + + var ( + aliasAddr1 = tpkg.RandAliasAddress() + ) + + inputs := iotago.OutputSet{ + inputIDs[0]: &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasAddr1.AliasID(), + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: ident1}, + &iotago.GovernorAddressUnlockCondition{Address: ident2}, + }, + }, + inputIDs[1]: &iotago.BasicOutput{ + Amount: 100, + Conditions: iotago.UnlockConditions{ + &iotago.AddressUnlockCondition{Address: aliasAddr1}, + }, + }, + } + + essence := &iotago.TransactionEssence{ + Inputs: inputIDs.UTXOInputs(), + Outputs: iotago.Outputs{ + &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasAddr1.AliasID(), + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: ident1}, + &iotago.GovernorAddressUnlockCondition{Address: ident2}, + }, + }, + }, + } + + sigs, err := essence.Sign(inputIDs.OrderedSet(inputs).MustCommitment(), ident2AddressKeys) + require.NoError(t, err) + + return test{ + name: "fail - alias output not state transitioning", + svCtx: &iotago.SemanticValidationContext{ExtParas: &iotago.ExternalUnlockParameters{}}, + inputs: inputs, + tx: &iotago.Transaction{ + Essence: essence, + Unlocks: iotago.Unlocks{ + &iotago.SignatureUnlock{Signature: sigs[0]}, + &iotago.AliasUnlock{Reference: 0}, + }, + }, + wantErr: iotago.ErrInvalidInputUnlock, + } + }(), } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 9be7dc6b659b11d9a1377adce243bb8186984cd0 Mon Sep 17 00:00:00 2001 From: Levente Pap Date: Thu, 25 Aug 2022 13:30:54 +0200 Subject: [PATCH 3/8] Add test cases for sender - Alias address can't be used as sender if alias is governance transitioned - Governor address can be used as sender if alias is governance transitioned --- transaction_test.go | 100 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/transaction_test.go b/transaction_test.go index bf89a5938..a4ac275b3 100644 --- a/transaction_test.go +++ b/transaction_test.go @@ -1828,6 +1828,106 @@ func TestTxSemanticOutputsSender(t *testing.T) { wantErr: iotago.ErrSenderFeatureNotUnlocked, } }(), + func() test { + _, stateController, _ := tpkg.RandEd25519Identity() + _, governor, governorAddrKeys := tpkg.RandEd25519Identity() + inputIDs := tpkg.RandOutputIDs(1) + aliasAddr := tpkg.RandAliasAddress() + aliasId := aliasAddr.AliasID() + + inputs := iotago.OutputSet{ + inputIDs[0]: &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasId, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: stateController}, + &iotago.GovernorAddressUnlockCondition{Address: governor}, + }, + }, + } + + essence := &iotago.TransactionEssence{ + Inputs: inputIDs.UTXOInputs(), + Outputs: iotago.Outputs{ + &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasId, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: stateController}, + &iotago.GovernorAddressUnlockCondition{Address: governor}, + }, + Features: iotago.Features{ + &iotago.SenderFeature{Address: aliasAddr}, + }, + }, + }, + } + sigs, err := essence.Sign(inputIDs.OrderedSet(inputs).MustCommitment(), governorAddrKeys) + require.NoError(t, err) + + return test{ + name: "fail - sender not unlocked due to governance transition", + svCtx: &iotago.SemanticValidationContext{ExtParas: &iotago.ExternalUnlockParameters{}}, + inputs: inputs, + tx: &iotago.Transaction{ + Essence: essence, + Unlocks: iotago.Unlocks{ + &iotago.SignatureUnlock{Signature: sigs[0]}, + }, + }, + wantErr: iotago.ErrSenderFeatureNotUnlocked, + } + }(), + func() test { + _, stateController, _ := tpkg.RandEd25519Identity() + _, governor, governorAddrKeys := tpkg.RandEd25519Identity() + inputIDs := tpkg.RandOutputIDs(1) + aliasAddr := tpkg.RandAliasAddress() + aliasId := aliasAddr.AliasID() + + inputs := iotago.OutputSet{ + inputIDs[0]: &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasId, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: stateController}, + &iotago.GovernorAddressUnlockCondition{Address: governor}, + }, + }, + } + + essence := &iotago.TransactionEssence{ + Inputs: inputIDs.UTXOInputs(), + Outputs: iotago.Outputs{ + &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasId, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: stateController}, + &iotago.GovernorAddressUnlockCondition{Address: governor}, + }, + Features: iotago.Features{ + &iotago.SenderFeature{Address: governor}, + }, + }, + }, + } + sigs, err := essence.Sign(inputIDs.OrderedSet(inputs).MustCommitment(), governorAddrKeys) + require.NoError(t, err) + + return test{ + name: "ok - sender is governor address", + svCtx: &iotago.SemanticValidationContext{ExtParas: &iotago.ExternalUnlockParameters{}}, + inputs: inputs, + tx: &iotago.Transaction{ + Essence: essence, + Unlocks: iotago.Unlocks{ + &iotago.SignatureUnlock{Signature: sigs[0]}, + }, + }, + wantErr: nil, + } + }(), } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From aee21f601ff2d1d0d3f65e47a459e72a8d4318c4 Mon Sep 17 00:00:00 2001 From: Levente Pap Date: Thu, 25 Aug 2022 13:41:59 +0200 Subject: [PATCH 4/8] Add test case - Alias Address can be used as Sender because state transition unlocks it --- transaction_test.go | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/transaction_test.go b/transaction_test.go index a4ac275b3..2edeeb31a 100644 --- a/transaction_test.go +++ b/transaction_test.go @@ -1878,6 +1878,59 @@ func TestTxSemanticOutputsSender(t *testing.T) { wantErr: iotago.ErrSenderFeatureNotUnlocked, } }(), + func() test { + _, stateController, stateControllerAddrKeys := tpkg.RandEd25519Identity() + _, governor, _ := tpkg.RandEd25519Identity() + inputIDs := tpkg.RandOutputIDs(1) + aliasAddr := tpkg.RandAliasAddress() + aliasId := aliasAddr.AliasID() + currentStateIndex := uint32(1) + + inputs := iotago.OutputSet{ + inputIDs[0]: &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasId, + StateIndex: currentStateIndex, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: stateController}, + &iotago.GovernorAddressUnlockCondition{Address: governor}, + }, + }, + } + + essence := &iotago.TransactionEssence{ + Inputs: inputIDs.UTXOInputs(), + Outputs: iotago.Outputs{ + &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasId, + StateIndex: currentStateIndex + 1, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: stateController}, + &iotago.GovernorAddressUnlockCondition{Address: governor}, + }, + Features: iotago.Features{ + &iotago.SenderFeature{Address: aliasAddr}, + }, + }, + }, + } + sigs, err := essence.Sign(inputIDs.OrderedSet(inputs).MustCommitment(), stateControllerAddrKeys) + require.NoError(t, err) + + return test{ + name: "ok - alias addr unlocked with state transition", + svCtx: &iotago.SemanticValidationContext{ExtParas: &iotago.ExternalUnlockParameters{}}, + inputs: inputs, + tx: &iotago.Transaction{ + Essence: essence, + Unlocks: iotago.Unlocks{ + &iotago.SignatureUnlock{Signature: sigs[0]}, + }, + }, + wantErr: nil, + } + }(), func() test { _, stateController, _ := tpkg.RandEd25519Identity() _, governor, governorAddrKeys := tpkg.RandEd25519Identity() From 917c3231a12e0e2aba98e930dc32c17220e0babc Mon Sep 17 00:00:00 2001 From: Luca Moser Date: Thu, 25 Aug 2022 15:13:31 +0200 Subject: [PATCH 5/8] mark alias output not as unlocked if it isn't state transitioning --- transaction.go | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/transaction.go b/transaction.go index 858860431..48cdad3d7 100644 --- a/transaction.go +++ b/transaction.go @@ -480,31 +480,16 @@ func TxSemanticInputUnlocks() TxSemanticValidationFunc { if chainID.Empty() { chainID = chainID.(UTXOIDChainID).FromOutputID(svCtx.WorkingSet.UTXOInputAtIndex(uint16(inputIndex)).Ref()) } - svCtx.WorkingSet.UnlockedIdents.AddUnlockedChain(chainID.ToAddress(), uint16(inputIndex)) - } - } - // check whether any alias output which is referenced is not doing a state transition - for _, v := range svCtx.WorkingSet.UnlockedIdents { - if len(v.ReferencedBy) == 0 { - continue - } - - input := svCtx.WorkingSet.Inputs[v.UnlockedAt] - current, ok := input.(*AliasOutput) - if !ok { - continue - } - - // there can be multiple entries given a chain output - aliasAddr, ok := v.Ident.(*AliasAddress) - if !ok { - continue - } + // for alias outputs which are not state transitioning, we do not add it to the set of unlocked chains + if current, ok := chainConstrOutput.(*AliasOutput); ok { + next, hasNextState := svCtx.WorkingSet.OutChains[chainID] + if !hasNextState || (current.StateIndex+1 != next.(*AliasOutput).StateIndex) { + continue + } + } - next, hasNextState := svCtx.WorkingSet.OutChains[aliasAddr.Chain()] - if !hasNextState || (current.StateIndex+1 != next.(*AliasOutput).StateIndex) { - return fmt.Errorf("%w: input alias output at %d is referenced by %v, but the alias output is not state transitioning", ErrInvalidInputUnlock, v.UnlockedAt, v.ReferencedBy) + svCtx.WorkingSet.UnlockedIdents.AddUnlockedChain(chainID.ToAddress(), uint16(inputIndex)) } } From 95b4ca7f9185d427795814635a487835614b9812 Mon Sep 17 00:00:00 2001 From: Levente Pap Date: Thu, 25 Aug 2022 17:53:30 +0200 Subject: [PATCH 6/8] Add issuer semantic validation test cases - Issuer is governance transitioned alias address => fail - Issuer is state transitioned alias address => ok - Issuer is governor addr that is gov. transitioning an alias => ok --- transaction_test.go | 219 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) diff --git a/transaction_test.go b/transaction_test.go index 2edeeb31a..6970f5933 100644 --- a/transaction_test.go +++ b/transaction_test.go @@ -1999,6 +1999,225 @@ func TestTxSemanticOutputsSender(t *testing.T) { } } +func TestTxSemanticOutputsIssuer(t *testing.T) { + type test struct { + name string + svCtx *iotago.SemanticValidationContext + inputs iotago.OutputSet + tx *iotago.Transaction + wantErr error + } + tests := []test{ + func() test { + _, ident1, ident1AddrKeys := tpkg.RandEd25519Identity() + _, stateController, _ := tpkg.RandEd25519Identity() + _, governor, governorAddrKeys := tpkg.RandEd25519Identity() + inputIDs := tpkg.RandOutputIDs(2) + aliasAddr := tpkg.RandAliasAddress() + aliasId := aliasAddr.AliasID() + + inputs := iotago.OutputSet{ + inputIDs[0]: &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasId, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: stateController}, + &iotago.GovernorAddressUnlockCondition{Address: governor}, + }, + }, + inputIDs[1]: &iotago.BasicOutput{ + Amount: 100, + Conditions: iotago.UnlockConditions{ + &iotago.AddressUnlockCondition{Address: ident1}, + }, + }, + } + + essence := &iotago.TransactionEssence{ + Inputs: inputIDs.UTXOInputs(), + Outputs: iotago.Outputs{ + &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasId, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: stateController}, + &iotago.GovernorAddressUnlockCondition{Address: governor}, + }, + }, + &iotago.NFTOutput{ + Amount: 100, + Conditions: iotago.UnlockConditions{ + &iotago.AddressUnlockCondition{Address: ident1}, + }, + ImmutableFeatures: iotago.Features{ + &iotago.IssuerFeature{Address: aliasAddr}, + }, + }, + }, + } + sigs, err := essence.Sign(inputIDs.OrderedSet(inputs).MustCommitment(), governorAddrKeys, ident1AddrKeys) + require.NoError(t, err) + + return test{ + name: "fail - issuer not unlocked due to governance transition", + svCtx: &iotago.SemanticValidationContext{ExtParas: &iotago.ExternalUnlockParameters{}}, + inputs: inputs, + tx: &iotago.Transaction{ + Essence: essence, + Unlocks: iotago.Unlocks{ + &iotago.SignatureUnlock{Signature: sigs[0]}, + &iotago.SignatureUnlock{Signature: sigs[1]}, + }, + }, + wantErr: iotago.ErrIssuerFeatureNotUnlocked, + } + }(), + func() test { + _, ident1, ident1AddrKeys := tpkg.RandEd25519Identity() + _, stateController, stateControllerAddrKeys := tpkg.RandEd25519Identity() + _, governor, _ := tpkg.RandEd25519Identity() + inputIDs := tpkg.RandOutputIDs(2) + aliasAddr := tpkg.RandAliasAddress() + aliasId := aliasAddr.AliasID() + currentStateIndex := uint32(1) + + inputs := iotago.OutputSet{ + inputIDs[0]: &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasId, + StateIndex: currentStateIndex, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: stateController}, + &iotago.GovernorAddressUnlockCondition{Address: governor}, + }, + }, + inputIDs[1]: &iotago.BasicOutput{ + Amount: 100, + Conditions: iotago.UnlockConditions{ + &iotago.AddressUnlockCondition{Address: ident1}, + }, + }, + } + + essence := &iotago.TransactionEssence{ + Inputs: inputIDs.UTXOInputs(), + Outputs: iotago.Outputs{ + &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasId, + StateIndex: currentStateIndex + 1, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: stateController}, + &iotago.GovernorAddressUnlockCondition{Address: governor}, + }, + }, + &iotago.NFTOutput{ + Amount: 100, + Conditions: iotago.UnlockConditions{ + &iotago.AddressUnlockCondition{Address: ident1}, + }, + ImmutableFeatures: iotago.Features{ + &iotago.IssuerFeature{Address: aliasAddr}, + }, + }, + }, + } + sigs, err := essence.Sign(inputIDs.OrderedSet(inputs).MustCommitment(), stateControllerAddrKeys, ident1AddrKeys) + require.NoError(t, err) + + return test{ + name: "ok - issuer unlocked with state transition", + svCtx: &iotago.SemanticValidationContext{ExtParas: &iotago.ExternalUnlockParameters{}}, + inputs: inputs, + tx: &iotago.Transaction{ + Essence: essence, + Unlocks: iotago.Unlocks{ + &iotago.SignatureUnlock{Signature: sigs[0]}, + &iotago.SignatureUnlock{Signature: sigs[1]}, + }, + }, + wantErr: nil, + } + }(), + func() test { + _, ident1, ident1AddrKeys := tpkg.RandEd25519Identity() + _, stateController, _ := tpkg.RandEd25519Identity() + _, governor, governorAddrKeys := tpkg.RandEd25519Identity() + inputIDs := tpkg.RandOutputIDs(2) + aliasAddr := tpkg.RandAliasAddress() + aliasId := aliasAddr.AliasID() + + inputs := iotago.OutputSet{ + inputIDs[0]: &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasId, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: stateController}, + &iotago.GovernorAddressUnlockCondition{Address: governor}, + }, + }, + inputIDs[1]: &iotago.BasicOutput{ + Amount: 100, + Conditions: iotago.UnlockConditions{ + &iotago.AddressUnlockCondition{Address: ident1}, + }, + }, + } + + essence := &iotago.TransactionEssence{ + Inputs: inputIDs.UTXOInputs(), + Outputs: iotago.Outputs{ + &iotago.AliasOutput{ + Amount: 100, + AliasID: aliasId, + Conditions: iotago.UnlockConditions{ + &iotago.StateControllerAddressUnlockCondition{Address: stateController}, + &iotago.GovernorAddressUnlockCondition{Address: governor}, + }, + }, + &iotago.NFTOutput{ + Amount: 100, + Conditions: iotago.UnlockConditions{ + &iotago.AddressUnlockCondition{Address: ident1}, + }, + ImmutableFeatures: iotago.Features{ + &iotago.IssuerFeature{Address: governor}, + }, + }, + }, + } + sigs, err := essence.Sign(inputIDs.OrderedSet(inputs).MustCommitment(), governorAddrKeys, ident1AddrKeys) + require.NoError(t, err) + + return test{ + name: "ok - issuer is the governor", + svCtx: &iotago.SemanticValidationContext{ExtParas: &iotago.ExternalUnlockParameters{}}, + inputs: inputs, + tx: &iotago.Transaction{ + Essence: essence, + Unlocks: iotago.Unlocks{ + &iotago.SignatureUnlock{Signature: sigs[0]}, + &iotago.SignatureUnlock{Signature: sigs[1]}, + }, + }, + wantErr: nil, + } + }(), + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + err := tt.tx.SemanticallyValidate(tt.svCtx, tt.inputs) + if tt.wantErr != nil { + require.ErrorIs(t, err, tt.wantErr) + return + } + + require.NoError(t, err) + }) + } +} + func TestTxSemanticTimelocks(t *testing.T) { type test struct { name string From 9777306cf1cd15f0d3257e613177013b4538733c Mon Sep 17 00:00:00 2001 From: muXxer Date: Thu, 25 Aug 2022 22:35:45 +0200 Subject: [PATCH 7/8] Fix formatting of address --- signature_ed25519.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signature_ed25519.go b/signature_ed25519.go index cdd1e0144..6fa02c5f7 100644 --- a/signature_ed25519.go +++ b/signature_ed25519.go @@ -44,7 +44,7 @@ func (e *Ed25519Signature) Valid(msg []byte, addr *Ed25519Address) error { // an address is the Blake2b 256 hash of the public key addrFromPubKey := Ed25519AddressFromPubKey(e.PublicKey[:]) if !bytes.Equal(addr[:], addrFromPubKey[:]) { - return fmt.Errorf("%w: address %s, address from public key %v", ErrEd25519PubKeyAndAddrMismatch, EncodeHex(addr[:]), addrFromPubKey) + return fmt.Errorf("%w: address %s, address from public key %v", ErrEd25519PubKeyAndAddrMismatch, EncodeHex(addr[:]), EncodeHex(addrFromPubKey[:])) } if valid := iotagoEd25519.Verify(e.PublicKey[:], msg, e.Signature[:]); !valid { return fmt.Errorf("%w: address %s, public key %v, signature %v", ErrEd25519SignatureInvalid, EncodeHex(addr[:]), EncodeHex(e.PublicKey[:]), EncodeHex(e.Signature[:])) From 6153f77454823190878674a45a9a44b02ce70086 Mon Sep 17 00:00:00 2001 From: Luca Moser Date: Fri, 26 Aug 2022 12:12:20 +0200 Subject: [PATCH 8/8] add checked typed assert for alias output --- transaction.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/transaction.go b/transaction.go index 48cdad3d7..9c44b80f0 100644 --- a/transaction.go +++ b/transaction.go @@ -482,9 +482,15 @@ func TxSemanticInputUnlocks() TxSemanticValidationFunc { } // for alias outputs which are not state transitioning, we do not add it to the set of unlocked chains - if current, ok := chainConstrOutput.(*AliasOutput); ok { + if currentAlias, ok := chainConstrOutput.(*AliasOutput); ok { next, hasNextState := svCtx.WorkingSet.OutChains[chainID] - if !hasNextState || (current.StateIndex+1 != next.(*AliasOutput).StateIndex) { + if !hasNextState { + continue + } + // note that isAlias should never be false in practice, + // but we add it anyway as an additional safeguard + nextAlias, isAlias := next.(*AliasOutput) + if !isAlias || (currentAlias.StateIndex+1 != nextAlias.StateIndex) { continue } }