Skip to content

Commit 0bd753d

Browse files
Merge branch 'main' into feat/task-delegation-adaptive-polling-shutdown-fix
2 parents 83e8ba2 + 7b21948 commit 0bd753d

393 files changed

Lines changed: 99286 additions & 45025 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/e2e-integration.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ jobs:
2424
- name: Checkout Repository
2525
uses: actions/checkout@v4
2626

27+
- name: Check for Conflict Markers
28+
run: |
29+
chmod +x scripts/check-conflict-markers.sh
30+
./scripts/check-conflict-markers.sh
31+
2732
- name: Set up Node.js
2833
uses: actions/setup-node@v4
2934
with:
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: End-to-End Stress & Chaos Engineering Benchmark Suite
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
pull_request:
7+
branches: [ main, master ]
8+
9+
jobs:
10+
stress-benchmark:
11+
name: Stress & Chaos Load Benchmark Suite
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout Repository
16+
uses: actions/checkout@v4
17+
18+
- name: Set up Node.js
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: 20
22+
cache: 'npm'
23+
24+
- name: Run End-to-End Stress & Chaos Benchmark Suite
25+
run: |
26+
node tests/stress/load_stress_suite.js
27+
28+
- name: Upload Benchmark Report Artifact
29+
uses: actions/upload-artifact@v4
30+
with:
31+
name: stress-benchmark-report
32+
path: tests/stress/stress-benchmark-report.json

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,9 @@ docker-compose.*.override.yml
8383
# Test snapshots
8484
__snapshots__/
8585
*.snap
86+
87+
# Git merge conflict dumps & temporary test scripts
88+
conflicts_*.txt
89+
merge_output_*.txt
90+
test-rpc.js
91+

.husky/pre-commit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
./scripts/check-conflict-markers.sh
12
npx lint-staged

backend-abi-registry/errorCodes.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* @fileoverview Canonical SoroTask error codes and human-readable message decoder.
3+
* Maps categorized on-chain Soroban contracterror discriminants into human-readable error descriptions.
4+
* @module backend-abi-registry/errorCodes
5+
*/
6+
7+
const ERROR_CODES = {
8+
// ── 100..199: Authorization & Role-Based Access ──────────────────────────────
9+
100: { name: 'Unauthorized', category: 'Auth', message: 'Caller is not authorized to perform this action' },
10+
101: { name: 'UnauthorizedSlasher', category: 'Auth', message: 'Caller is not authorized to slash keeper' },
11+
102: { name: 'OperatorAlreadySet', category: 'Auth', message: 'Operator address has already been set' },
12+
103: { name: 'NotInitialized', category: 'Auth', message: 'Contract has not been initialized' },
13+
104: { name: 'AlreadyInitialized', category: 'Auth', message: 'Contract has already been initialized' },
14+
105: { name: 'FeatureDisabled', category: 'Auth', message: 'Requested protocol feature is disabled' },
15+
106: { name: 'InsufficientDelegation', category: 'Auth', message: 'Keeper delegation amount is insufficient' },
16+
107: { name: 'InvalidCommissionRate', category: 'Auth', message: 'Commission rate exceeds allowable maximum' },
17+
18+
// ── 200..299: Task Lifecycle & Validation ────────────────────────────────────
19+
200: { name: 'InvalidInterval', category: 'TaskValidation', message: 'Task execution interval is invalid' },
20+
201: { name: 'TaskPaused', category: 'TaskValidation', message: 'Task execution is currently paused' },
21+
202: { name: 'TaskAlreadyPaused', category: 'TaskValidation', message: 'Task is already in a paused state' },
22+
203: { name: 'TaskAlreadyActive', category: 'TaskValidation', message: 'Task is already in an active state' },
23+
204: { name: 'TaskNotFound', category: 'TaskValidation', message: 'Specified task ID does not exist' },
24+
205: { name: 'DuplicateTask', category: 'TaskValidation', message: 'Duplicate task registration detected' },
25+
206: { name: 'InvalidPayload', category: 'TaskValidation', message: 'Task payload or arguments are malformed' },
26+
207: { name: 'ArgsTooMany', category: 'TaskValidation', message: 'Number of task arguments exceeds limit' },
27+
208: { name: 'ArgsTooLarge', category: 'TaskValidation', message: 'Total size of task arguments exceeds limit' },
28+
209: { name: 'BountyBelowMinimum', category: 'TaskValidation', message: 'Task execution bounty is below required minimum' },
29+
210: { name: 'InvalidBounty', category: 'TaskValidation', message: 'Task execution bounty parameters are invalid' },
30+
211: { name: 'InvalidUpgradeVersion', category: 'TaskValidation', message: 'Target WASM upgrade version is invalid' },
31+
212: { name: 'InvalidInsurancePolicy', category: 'TaskValidation', message: 'Insurance policy parameters are invalid' },
32+
33+
// ── 300..399: Execution, Dependency & Reentrancy ─────────────────────────────
34+
300: { name: 'ReentrantCall', category: 'Execution', message: 'Reentrancy guard triggered on recursive entry' },
35+
301: { name: 'SelfDependency', category: 'Execution', message: 'Task cannot depend on itself' },
36+
302: { name: 'DependencyNotFound', category: 'Execution', message: 'Required task dependency not found' },
37+
303: { name: 'CircularDependency', category: 'Execution', message: 'Circular dependency cycle detected' },
38+
304: { name: 'DependencyBlocked', category: 'Execution', message: 'Task execution blocked by unresolved dependencies' },
39+
305: { name: 'DependencyLimitExceeded', category: 'Execution', message: 'Maximum dependency count exceeded' },
40+
306: { name: 'DependencyDepthExceeded', category: 'Execution', message: 'Maximum dependency tree depth exceeded' },
41+
307: { name: 'KeeperStakeTooLow', category: 'Execution', message: 'Keeper active stake is below minimum threshold' },
42+
308: { name: 'EmptyBundle', category: 'Execution', message: 'Task execution bundle contains zero steps' },
43+
309: { name: 'BundleTooLarge', category: 'Execution', message: 'Task bundle size exceeds block limit' },
44+
310: { name: 'BundleStepFailed', category: 'Execution', message: 'One or more bundle execution steps failed' },
45+
311: { name: 'BlockExecutionLimitReached', category: 'Execution', message: 'Per-block task execution cap reached' },
46+
312: { name: 'DecryptionFailed', category: 'Execution', message: 'Encrypted task parameter decryption failed' },
47+
313: { name: 'OptimisticClaimPending', category: 'Execution', message: 'Optimistic challenge claim is currently pending' },
48+
314: { name: 'NoOptimisticClaim', category: 'Execution', message: 'No active optimistic challenge claim found' },
49+
315: { name: 'ChallengeWindowClosed', category: 'Execution', message: 'Optimistic challenge window has expired' },
50+
316: { name: 'ChallengeWindowActive', category: 'Execution', message: 'Challenge window is still active' },
51+
317: { name: 'FraudProofInvalid', category: 'Execution', message: 'Supplied optimistic fraud proof is invalid' },
52+
53+
// ── 400..499: Oracles, VRF & ZK Verifier ─────────────────────────────────────
54+
400: { name: 'OracleNotSet', category: 'Oracle', message: 'Required price or data oracle is not configured' },
55+
401: { name: 'OracleRequestFailed', category: 'Oracle', message: 'Oracle data request failed or reverted' },
56+
402: { name: 'OracleInvalidResponse', category: 'Oracle', message: 'Oracle returned invalid or unparseable data' },
57+
403: { name: 'OracleTimeout', category: 'Oracle', message: 'Oracle response exceeded timeout window' },
58+
404: { name: 'OracleUnsupportedProvider', category: 'Oracle', message: 'Specified oracle provider is not supported' },
59+
405: { name: 'VrfOracleNotSet', category: 'Oracle', message: 'VRF randomness oracle is not configured' },
60+
406: { name: 'InvalidVrfRequest', category: 'Oracle', message: 'VRF randomness request parameters are invalid' },
61+
407: { name: 'VrfRequestFailed', category: 'Oracle', message: 'VRF randomness fulfillment request failed' },
62+
408: { name: 'VrfAlreadyFulfilled', category: 'Oracle', message: 'VRF request has already been fulfilled' },
63+
409: { name: 'InvalidZkProof', category: 'Oracle', message: 'Zero-knowledge verification proof is invalid' },
64+
410: { name: 'InvalidVdfProof', category: 'Oracle', message: 'Verifiable delay function proof is invalid' },
65+
66+
// ── 500..599: Yield, Flash Swaps & Treasury ──────────────────────────────────
67+
500: { name: 'InsufficientBalance', category: 'Treasury', message: 'Contract or task escrow balance is insufficient' },
68+
501: { name: 'YieldStrategyNotInitialized', category: 'Treasury', message: 'Yield strategy adapter has not been initialized' },
69+
502: { name: 'InvalidYieldStrategy', category: 'Treasury', message: 'Yield strategy configuration is invalid' },
70+
503: { name: 'YieldHarvestFailed', category: 'Treasury', message: 'Harvesting yield from external protocol failed' },
71+
504: { name: 'InsufficientYield', category: 'Treasury', message: 'Yield generated is below expected threshold' },
72+
505: { name: 'FlashSwapFailed', category: 'Treasury', message: 'Flash swap callback execution failed' },
73+
506: { name: 'InsufficientFlashProfit', category: 'Treasury', message: 'Flash swap did not generate required minimum profit' },
74+
507: { name: 'InvalidSlippage', category: 'Treasury', message: 'Slippage parameter exceeds maximum allowed tolerance' },
75+
76+
// ── 600..699: Volatility & Circuit Breakers ──────────────────────────────────
77+
600: { name: 'VolatilityExceeded', category: 'Volatility', message: 'Asset volatility exceeds allowed tolerance limit' },
78+
601: { name: 'VolatilityCircuitBreakerTripped', category: 'Volatility', message: 'Volatility circuit breaker tripped; execution paused' },
79+
602: { name: 'VolatilityTimelockActive', category: 'Volatility', message: 'Volatility timelock is active; cannot execute until window expires' },
80+
};
81+
82+
/**
83+
* Decodes an on-chain numeric error code into a human-readable error description.
84+
*
85+
* @param {number} code - On-chain error discriminant.
86+
* @returns {{ code: number, name: string, category: string, message: string }} Error metadata.
87+
*/
88+
function decodeErrorCode(code) {
89+
const info = ERROR_CODES[code];
90+
if (info) {
91+
return { code, ...info };
92+
}
93+
return {
94+
code,
95+
name: 'UnknownError',
96+
category: 'Unknown',
97+
message: `Unknown contract error code: ${code}`,
98+
};
99+
}
100+
101+
module.exports = {
102+
ERROR_CODES,
103+
decodeErrorCode,
104+
};

backend-abi-registry/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const parser = require('./parser');
22
const registry = require('./registry');
33
const errorHandler = require('./errorHandler');
4+
const errorCodes = require('./errorCodes');
45
const Monitor = require('./monitor');
56
const { AbiCache } = require('./abiCache');
67

@@ -30,6 +31,14 @@ class ABIRegistryService {
3031
return errorHandler;
3132
}
3233

34+
getErrorCodes() {
35+
return errorCodes;
36+
}
37+
38+
decodeErrorCode(code) {
39+
return errorCodes.decodeErrorCode(code);
40+
}
41+
3342
async getABI(contractId, wasmHash, fetchABI) {
3443
const cached = await this.cache.getPersistent(contractId, wasmHash);
3544
if (cached) return cached;

backend-abi-registry/tests/abi-registry.test.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,5 +240,22 @@ describe('ABIRegistryService', () => {
240240
expect(abiRegistryService.getRegistry()).toBe(registry);
241241
expect(abiRegistryService.getErrorHandler()).toBe(errorHandler);
242242
});
243+
244+
it('should decode canonical error codes correctly', () => {
245+
const decoded100 = abiRegistryService.decodeErrorCode(100);
246+
expect(decoded100.name).toBe('Unauthorized');
247+
expect(decoded100.category).toBe('Auth');
248+
249+
const decoded300 = abiRegistryService.decodeErrorCode(300);
250+
expect(decoded300.name).toBe('ReentrantCall');
251+
expect(decoded300.category).toBe('Execution');
252+
253+
const decoded507 = abiRegistryService.decodeErrorCode(507);
254+
expect(decoded507.name).toBe('InvalidSlippage');
255+
expect(decoded507.category).toBe('Treasury');
256+
257+
const decodedUnknown = abiRegistryService.decodeErrorCode(9999);
258+
expect(decodedUnknown.name).toBe('UnknownError');
259+
});
243260
});
244261
});

conflicts_554.txt

Lines changed: 0 additions & 2 deletions
This file was deleted.

conflicts_626.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

conflicts_638.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)