|
| 1 | +/* |
| 2 | +Copyright IBM Corp. All Rights Reserved. |
| 3 | +
|
| 4 | +SPDX-License-Identifier: Apache-2.0 |
| 5 | +*/ |
| 6 | + |
| 7 | +package audit |
| 8 | + |
| 9 | +import ( |
| 10 | + "testing" |
| 11 | + |
| 12 | + protoactions "github.com/LFDT-Panurus/panurus/token/core/fabtoken/protos-go/v1/actions" |
| 13 | + "github.com/LFDT-Panurus/panurus/token/core/fabtoken/v1/actions" |
| 14 | + "github.com/LFDT-Panurus/panurus/token/driver" |
| 15 | + "github.com/LFDT-Panurus/panurus/token/driver/protos-go/v1/request" |
| 16 | + "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/proto" |
| 17 | + "github.com/stretchr/testify/require" |
| 18 | +) |
| 19 | + |
| 20 | +// marshalIssueAction builds a serialized fabtoken issue action with the given |
| 21 | +// number of outputs. |
| 22 | +func marshalIssueAction(t *testing.T, outputs int) []byte { |
| 23 | + t.Helper() |
| 24 | + ia := &protoactions.IssueAction{ |
| 25 | + Version: actions.ProtocolV1, |
| 26 | + Issuer: nil, |
| 27 | + } |
| 28 | + for range outputs { |
| 29 | + ia.Outputs = append(ia.Outputs, &protoactions.IssueActionOutput{Token: &protoactions.Token{Owner: []byte("o"), Type: "TYPE", Quantity: "0x1"}}) |
| 30 | + } |
| 31 | + raw, err := proto.Marshal(ia) |
| 32 | + require.NoError(t, err) |
| 33 | + |
| 34 | + return raw |
| 35 | +} |
| 36 | + |
| 37 | +// marshalTransferAction builds a serialized fabtoken transfer action with the |
| 38 | +// given number of inputs and outputs. |
| 39 | +func marshalTransferAction(t *testing.T, inputs, outputs int) []byte { |
| 40 | + t.Helper() |
| 41 | + ta := &protoactions.TransferAction{ |
| 42 | + Version: actions.ProtocolV1, |
| 43 | + } |
| 44 | + for range inputs { |
| 45 | + ta.Inputs = append(ta.Inputs, &protoactions.TransferActionInput{Input: &protoactions.Token{Owner: []byte("o"), Type: "TYPE", Quantity: "0x1"}}) |
| 46 | + } |
| 47 | + for range outputs { |
| 48 | + ta.Outputs = append(ta.Outputs, &protoactions.TransferActionOutput{Token: &protoactions.Token{Owner: []byte("o"), Type: "TYPE", Quantity: "0x1"}}) |
| 49 | + } |
| 50 | + raw, err := proto.Marshal(ta) |
| 51 | + require.NoError(t, err) |
| 52 | + |
| 53 | + return raw |
| 54 | +} |
| 55 | + |
| 56 | +func issueRequest(raw []byte) *driver.TokenRequest { |
| 57 | + return &driver.TokenRequest{ |
| 58 | + Actions: []*driver.TypedAction{{Type: request.ActionType_ACTION_TYPE_ISSUE, Raw: raw}}, |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +func transferRequest(raw []byte) *driver.TokenRequest { |
| 63 | + return &driver.TokenRequest{ |
| 64 | + Actions: []*driver.TypedAction{{Type: request.ActionType_ACTION_TYPE_TRANSFER, Raw: raw}}, |
| 65 | + } |
| 66 | +} |
| 67 | + |
| 68 | +// TestActionDeserializer_AppliesConfiguredLimits is a regression test for issue |
| 69 | +// #2028: the audit path must enforce the operator-configured resource limits, |
| 70 | +// not silently fall back to driver.DefaultResourceLimits(). It exercises a limit |
| 71 | +// tighter than the defaults so that a missing SetLimits call (the original bug) |
| 72 | +// would let the oversized action through and fail the test. |
| 73 | +func TestActionDeserializer_AppliesConfiguredLimits(t *testing.T) { |
| 74 | + custom := driver.DefaultResourceLimits() |
| 75 | + custom.MaxOutputs = 2 |
| 76 | + custom.MaxInputs = 2 |
| 77 | + d := &ActionDeserializer{Limits: custom} |
| 78 | + |
| 79 | + t.Run("issue within limit", func(t *testing.T) { |
| 80 | + _, _, err := d.DeserializeActions(issueRequest(marshalIssueAction(t, 2))) |
| 81 | + require.NoError(t, err) |
| 82 | + }) |
| 83 | + t.Run("issue exceeds configured limit", func(t *testing.T) { |
| 84 | + _, _, err := d.DeserializeActions(issueRequest(marshalIssueAction(t, 3))) |
| 85 | + require.ErrorIs(t, err, actions.ErrTooManyOutputs) |
| 86 | + }) |
| 87 | + |
| 88 | + t.Run("transfer within limit", func(t *testing.T) { |
| 89 | + _, _, err := d.DeserializeActions(transferRequest(marshalTransferAction(t, 2, 2))) |
| 90 | + require.NoError(t, err) |
| 91 | + }) |
| 92 | + t.Run("transfer exceeds configured input limit", func(t *testing.T) { |
| 93 | + _, _, err := d.DeserializeActions(transferRequest(marshalTransferAction(t, 3, 1))) |
| 94 | + require.ErrorIs(t, err, actions.ErrTooManyInputs) |
| 95 | + }) |
| 96 | + t.Run("transfer exceeds configured output limit", func(t *testing.T) { |
| 97 | + _, _, err := d.DeserializeActions(transferRequest(marshalTransferAction(t, 1, 3))) |
| 98 | + require.ErrorIs(t, err, actions.ErrTooManyOutputs) |
| 99 | + }) |
| 100 | +} |
0 commit comments