Skip to content

Commit

Permalink
Do not allow nesting of restricted addresses in multi addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
muXxer committed Sep 18, 2023
1 parent c0bc5af commit 8e239d8
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 30 deletions.
20 changes: 2 additions & 18 deletions api_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var (
}

// multiAddressValidatorFunc is a validator which checks that:
// 1. MultiAddresses are not nested inside the MultiAddress.
// 1. ImplicitAccountCreationAddress, MultiAddresses, RestrictedAddress are not nested inside the MultiAddress.
// 2. "raw address part" of all addresses are unique (without type byte and capabilities).
// 3. The weight of each address is at least 1.
// 4. The threshold is smaller or equal to the cumulative weight of all addresses.
Expand All @@ -41,23 +41,7 @@ var (
case *MultiAddress:
return ierrors.Wrapf(ErrInvalidNestedAddressType, "address with index %d is a multi address inside a multi address", idx)
case *RestrictedAddress:
// a restricted address contains an underlying address which we need to check
switch underlyingAddr := addr.Address.(type) {
case *Ed25519Address:
addrWithoutTypeAndCapabilities = underlyingAddr[:]
case *AccountAddress:
addrWithoutTypeAndCapabilities = underlyingAddr[:]
case *NFTAddress:
addrWithoutTypeAndCapabilities = underlyingAddr[:]
case *ImplicitAccountCreationAddress:
return ierrors.Wrapf(ErrInvalidNestedAddressType, "address with index %d is an underlying implicit account creation address inside a restricted address inside a multi address", idx)
case *MultiAddress:
return ierrors.Wrapf(ErrInvalidNestedAddressType, "address with index %d is an underlying multi address inside a restricted address inside a multi address", idx)
case *RestrictedAddress:
return ierrors.Wrapf(ErrInvalidNestedAddressType, "address with index %d is an underlying restricted address inside a restricted address inside a multi address", idx)
default:
return ierrors.Wrapf(ErrUnknownAddrType, "address with index %d is a restricted address with an unknown underlying address type (%T) inside a multi address", idx, addr)
}
return ierrors.Wrapf(ErrInvalidNestedAddressType, "address with index %d is a restricted address inside a multi address", idx)
default:
return ierrors.Wrapf(ErrUnknownAddrType, "address with index %d has an unknown address type (%T) inside a multi address", idx, addr)
}
Expand Down
115 changes: 103 additions & 12 deletions vm/stardust/vm_stardust_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1749,7 +1749,7 @@ func TestStardustTransactionExecution_RestrictedAddress(t *testing.T) {
}
}

func TestStardustTransactionExecution_MultiUnlock(t *testing.T) {
func TestStardustTransactionExecution_MultiAddress(t *testing.T) {

var defaultAmount iotago.BaseToken = OneMi

Expand Down Expand Up @@ -3023,6 +3023,101 @@ func TestStardustTransactionExecution_MultiUnlock(t *testing.T) {
}
}(),

// fail - raw address part of all addresses inside MultiAddress need to be unique (needs to be checked on output side)
func() txExecTest {
return txExecTest{
name: "fail - raw address part of all addresses inside MultiAddress need to be unique (needs to be checked on output side)",
ed25519AddrCnt: 1,
addressesFunc: nil,
inputsFunc: func(ed25519Addresses []iotago.Address, testAddresses []iotago.Address) []iotago.Output {
return []iotago.Output{
&iotago.BasicOutput{
Amount: defaultAmount,
Conditions: iotago.BasicOutputUnlockConditions{
&iotago.AddressUnlockCondition{Address: ed25519Addresses[0]},
},
},
}
},
outputsFunc: func(ed25519Addresses []iotago.Address, testAddresses []iotago.Address, inputIDs iotago.OutputIDs, totalInputAmount iotago.BaseToken) iotago.TxEssenceOutputs {
return iotago.TxEssenceOutputs{
&iotago.BasicOutput{
Amount: totalInputAmount,
Conditions: iotago.BasicOutputUnlockConditions{
&iotago.AddressUnlockCondition{Address: &iotago.MultiAddress{
Addresses: []*iotago.AddressWithWeight{
// both have the same pubKeyHash
{
Address: &iotago.Ed25519Address{},
Weight: 1,
},
{
Address: &iotago.Ed25519Address{},
Weight: 1,
},
},
Threshold: 1,
}},
},
},
}
},
unlocksFunc: func(sigs []iotago.Signature, testAddresses []iotago.Address) iotago.Unlocks {
return iotago.Unlocks{
&iotago.SignatureUnlock{Signature: sigs[0]},
}
},
wantEncodeErr: serializer.ErrArrayValidationViolatesUniqueness,
wantExecuteErr: nil,
}
}(),

// fail - ImplicitAccountCreationAddress nested inside of a MultiAddress (needs to be checked on output side)
func() txExecTest {
return txExecTest{
name: "fail - ImplicitAccountCreationAddress nested inside of a MultiAddress (needs to be checked on output side)",
ed25519AddrCnt: 1,
addressesFunc: nil,
inputsFunc: func(ed25519Addresses []iotago.Address, testAddresses []iotago.Address) []iotago.Output {
return []iotago.Output{
&iotago.BasicOutput{
Amount: defaultAmount,
Conditions: iotago.BasicOutputUnlockConditions{
&iotago.AddressUnlockCondition{Address: ed25519Addresses[0]},
},
},
}
},
outputsFunc: func(ed25519Addresses []iotago.Address, testAddresses []iotago.Address, inputIDs iotago.OutputIDs, totalInputAmount iotago.BaseToken) iotago.TxEssenceOutputs {
return iotago.TxEssenceOutputs{
&iotago.BasicOutput{
Amount: totalInputAmount,
Conditions: iotago.BasicOutputUnlockConditions{
&iotago.AddressUnlockCondition{Address: &iotago.RestrictedAddress{
Address: &iotago.MultiAddress{
Addresses: []*iotago.AddressWithWeight{
{
Address: &iotago.ImplicitAccountCreationAddress{},
Weight: 1,
},
},
Threshold: 1,
},
}},
},
},
}
},
unlocksFunc: func(sigs []iotago.Signature, testAddresses []iotago.Address) iotago.Unlocks {
return iotago.Unlocks{
&iotago.SignatureUnlock{Signature: sigs[0]},
}
},
wantEncodeErr: iotago.ErrInvalidNestedAddressType,
wantExecuteErr: nil,
}
}(),

// fail - MultiAddress nested inside of a MultiAddress (needs to be checked on output side)
func() txExecTest {
return txExecTest{
Expand Down Expand Up @@ -3075,10 +3170,10 @@ func TestStardustTransactionExecution_MultiUnlock(t *testing.T) {
}
}(),

// fail - Raw address part of all addresses inside MultiAddress need to be unique (needs to be checked on output side)
// fail - RestrictedAddress nested inside of a MultiAddress (needs to be checked on output side)
func() txExecTest {
return txExecTest{
name: "fail - Raw address part of all addresses inside MultiAddress need to be unique (needs to be checked on output side)",
name: "fail - RestrictedAddress nested inside of a MultiAddress (needs to be checked on output side)",
ed25519AddrCnt: 1,
addressesFunc: nil,
inputsFunc: func(ed25519Addresses []iotago.Address, testAddresses []iotago.Address) []iotago.Output {
Expand All @@ -3098,31 +3193,27 @@ func TestStardustTransactionExecution_MultiUnlock(t *testing.T) {
Conditions: iotago.BasicOutputUnlockConditions{
&iotago.AddressUnlockCondition{Address: &iotago.MultiAddress{
Addresses: []*iotago.AddressWithWeight{
// both should have the same pubKeyHash
{
Address: &iotago.Ed25519Address{},
Weight: 1,
},
{
Address: &iotago.RestrictedAddress{
Address: &iotago.Ed25519Address{},
AllowedCapabilities: iotago.AddressCapabilitiesBitMask{0x55},
Address: ed25519Addresses[0],
AllowedCapabilities: iotago.AddressCapabilitiesBitMask{},
},
Weight: 2,
Weight: 1,
},
},
Threshold: 1,
}},
},
},
}

},
unlocksFunc: func(sigs []iotago.Signature, testAddresses []iotago.Address) iotago.Unlocks {
return iotago.Unlocks{
&iotago.SignatureUnlock{Signature: sigs[0]},
}
},
wantEncodeErr: serializer.ErrArrayValidationViolatesUniqueness,
wantEncodeErr: iotago.ErrInvalidNestedAddressType,
wantExecuteErr: nil,
}
}(),
Expand Down

0 comments on commit 8e239d8

Please sign in to comment.