Skip to content

Commit f3eaafb

Browse files
Effi-SAkramBitar
authored andcommitted
Updated limiting
Signed-off-by: Effi-S <effi.szt@gmail.com>
1 parent 2a9d181 commit f3eaafb

5 files changed

Lines changed: 125 additions & 6 deletions

File tree

token/core/fabtoken/v1/audit/auditor.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,19 @@ type ValidateTransferAuditFunc = common.ValidateTransferAuditFunc[*setup.PublicP
2828
type AuditContext = common.AuditContext[*setup.PublicParams, *actions.IssueAction, *actions.TransferAction, driver.Deserializer]
2929

3030
// ActionDeserializer deserializes fabtoken actions.
31-
type ActionDeserializer struct{}
31+
type ActionDeserializer struct {
32+
// Limits are the configured resource limits stamped onto each action before
33+
// deserialization, so the audit path enforces the same policy as the validator.
34+
Limits driver.ResourceLimits
35+
}
3236

3337
// DeserializeActions deserializes issue and transfer actions from a token request.
3438
func (a *ActionDeserializer) DeserializeActions(tr *driver.TokenRequest) ([]*actions.IssueAction, []*actions.TransferAction, error) {
3539
issues := tr.GetIssues()
3640
issueActions := make([]*actions.IssueAction, len(issues))
3741
for i := range issues {
3842
ia := &actions.IssueAction{}
43+
ia.SetLimits(a.Limits)
3944
if err := ia.Deserialize(issues[i]); err != nil {
4045
return nil, nil, err
4146
}
@@ -46,6 +51,7 @@ func (a *ActionDeserializer) DeserializeActions(tr *driver.TokenRequest) ([]*act
4651
transferActions := make([]*actions.TransferAction, len(transfers))
4752
for i := range transfers {
4853
ta := &actions.TransferAction{}
54+
ta.SetLimits(a.Limits)
4955
if err := ta.Deserialize(transfers[i]); err != nil {
5056
return nil, nil, err
5157
}
@@ -59,7 +65,11 @@ func (a *ActionDeserializer) DeserializeActions(tr *driver.TokenRequest) ([]*act
5965
type Auditor = common.Auditor[*setup.PublicParams, *actions.IssueAction, *actions.TransferAction, driver.Deserializer]
6066

6167
// NewAuditor creates a new Auditor for fabtoken validation.
62-
func NewAuditor(logger logging.Logger, tracer trace.Tracer, deserializer driver.Deserializer, pp *setup.PublicParams, precision uint64) *Auditor {
68+
//
69+
// limits are the configured resource limits; they are threaded into the
70+
// ActionDeserializer and applied to each action before deserialization so the
71+
// audit path enforces the same policy as the validator (see validator.go).
72+
func NewAuditor(logger logging.Logger, tracer trace.Tracer, deserializer driver.Deserializer, pp *setup.PublicParams, precision uint64, limits driver.ResourceLimits) *Auditor {
6373
issueValidators := []ValidateIssueAuditFunc{
6474
IssueAuditValidate(precision),
6575
}
@@ -73,7 +83,7 @@ func NewAuditor(logger logging.Logger, tracer trace.Tracer, deserializer driver.
7383
tracer,
7484
pp,
7585
deserializer,
76-
&ActionDeserializer{},
86+
&ActionDeserializer{Limits: limits},
7787
issueValidators,
7888
transferValidators,
7989
)
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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+
}

token/core/fabtoken/v1/auditor.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ type AuditorService struct {
2828
QueryEngine driver.QueryEngine
2929
tracer trace.Tracer
3030

31+
// Limits are the configured resource limits threaded into the auditor so the
32+
// audit path enforces the same policy as the validator (issue #2028).
33+
Limits driver.ResourceLimits
34+
3135
// AuditTokensNumRetries and AuditTokensRetryDelay control how AuditorCheck's
3236
// token lookup tolerates the pending-transaction read-timing race (issue #2105).
3337
// They default to common.DefaultAuditTokensNumRetries / DefaultAuditTokensRetryDelay
@@ -41,13 +45,17 @@ type AuditorService struct {
4145
// retryConfig sets the audit-token retry/backoff behavior of AuditorCheck; pass
4246
// common.DefaultAuditRetryConfig() for the built-in defaults or
4347
// common.LoadAuditRetryConfig(tmsConfig) to honor the per-TMS configuration file.
48+
//
49+
// limits are the configured resource limits; they are threaded into the auditor
50+
// so the audit path enforces the same policy as the validator (issue #2028).
4451
func NewAuditorService(
4552
logger logging.Logger,
4653
publicParametersManager common.PublicParametersManager[*setup.PublicParams],
4754
deserializer driver.Deserializer,
4855
queryEngine driver.QueryEngine,
4956
tracerProvider trace.TracerProvider,
5057
retryConfig common.AuditRetryConfig,
58+
limits driver.ResourceLimits,
5159
) *AuditorService {
5260
return &AuditorService{
5361
Logger: logger,
@@ -57,6 +65,7 @@ func NewAuditorService(
5765
tracer: tracerProvider.Tracer("auditor_service", tracing.WithMetricsOpts(tracing.MetricsOpts{})),
5866
AuditTokensNumRetries: retryConfig.NumRetries,
5967
AuditTokensRetryDelay: retryConfig.RetryDelay,
68+
Limits: limits,
6069
}
6170
}
6271

@@ -79,7 +88,7 @@ func (s *AuditorService) AuditorCheck(ctx context.Context, request *driver.Token
7988
}
8089

8190
pp := s.PublicParametersManager.PublicParams()
82-
auditor := audit.NewAuditor(s.Logger, s.tracer, s.Deserializer, pp, pp.Precision())
91+
auditor := audit.NewAuditor(s.Logger, s.tracer, s.Deserializer, pp, pp.Precision(), s.Limits)
8392
s.Logger.DebugfContext(ctx, "Start auditor check")
8493
err = auditor.Check(
8594
ctx,

token/core/fabtoken/v1/auditor_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func newAuditEnv(benchmarkCase *benchmark2.Case) (*auditEnv, error) {
112112
queryEngine := &mockQueryEngine{}
113113
tracerProvider := noop.NewTracerProvider()
114114

115-
as := v1.NewAuditorService(logger, publicParamsManager, deserializer, queryEngine, tracerProvider, common.DefaultAuditRetryConfig())
115+
as := v1.NewAuditorService(logger, publicParamsManager, deserializer, queryEngine, tracerProvider, common.DefaultAuditRetryConfig(), driver.DefaultResourceLimits())
116116

117117
// Create test data structures
118118
issueAction := &actions.IssueAction{

token/core/fabtoken/v1/driver/driver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ func (d *Driver) NewTokenService(tmsID driver.TMSID, publicParams []byte) (drive
182182
tmsConfig,
183183
metrics.NewIssueService(v1.NewIssueService(publicParamsManager, ws, deserializer), metricsProvider),
184184
metrics.NewTransferService(v1.NewTransferService(logger, publicParamsManager, ws, common.NewVaultTokenLoader(qe), deserializer), metricsProvider),
185-
metrics.NewAuditorService(v1.NewAuditorService(logger, publicParamsManager, deserializer, qe, d.tracerProvider, common.LoadAuditRetryConfig(tmsConfig)), metricsProvider),
185+
metrics.NewAuditorService(v1.NewAuditorService(logger, publicParamsManager, deserializer, qe, d.tracerProvider, common.LoadAuditRetryConfig(tmsConfig), limits), metricsProvider),
186186
metrics.NewTokensService(tokensService, metricsProvider),
187187
metrics.NewTokensUpgradeService(&v1.TokensUpgradeService{}, metricsProvider),
188188
authorization,

0 commit comments

Comments
 (0)