diff --git a/.github/workflows/build-lint-test.yml b/.github/workflows/build-lint-test.yml new file mode 100644 index 0000000..bc07193 --- /dev/null +++ b/.github/workflows/build-lint-test.yml @@ -0,0 +1,31 @@ +name: Build, Lint, and Test + +on: + workflow_call: + +jobs: + build-lint-test: + name: Build, Lint, and Test + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - uses: actions/checkout@v3 + - name: Build with Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: "npm" + - run: npm install --no-package-lock + - run: npm install --save-dev @nomicfoundation/solidity-analyzer-linux-x64-gnu @nx/nx-linux-x64-gnu + - name: Build + run: npm run build + - name: Lint + run: npm run lint + - name: Test + run: npm run test + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index df94e2c..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,41 +0,0 @@ - -# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs - -name: build - -on: - push: - branches: [ "main" ] - pull_request: - branches: - - '**' - -jobs: - build: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [18.x] - - steps: - - uses: actions/checkout@v3 - - name: Build with Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - run: npm install --no-package-lock - - run: npm install --save-dev @nomicfoundation/solidity-analyzer-linux-x64-gnu @nx/nx-linux-x64-gnu - - name: Build - run: npm run build - - name: Lint - run: npm run lint - - name: Test - run: npm run test - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v3 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/bundler-spec-test.yml b/.github/workflows/compliance.yml similarity index 90% rename from .github/workflows/bundler-spec-test.yml rename to .github/workflows/compliance.yml index 3cf8544..a9128f7 100644 --- a/.github/workflows/bundler-spec-test.yml +++ b/.github/workflows/compliance.yml @@ -1,20 +1,15 @@ name: compliance on: - push: - branches: [ "main" ] - pull_request: - branches: - - '**' + workflow_call: jobs: - bundler-spec-tests: + compliance: + name: compliance runs-on: ubuntu-latest - strategy: - matrix: - node-version: [18.x] - + matrix: + node-version: [18.x] steps: - uses: actions/checkout@v3 @@ -25,7 +20,7 @@ jobs: uses: "actions/setup-node@v3" with: node-version: ${{ matrix.node-version }} - cache: 'npm' + cache: "npm" - name: Checkout bundler spec tests uses: actions/checkout@v3 @@ -76,10 +71,10 @@ jobs: --exec "eth.sendTransaction({from: eth.accounts[0], to: \"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\", value: web3.toWei(4337, \"ether\")})" \ attach http://localhost:8545/ - - name: Install Transeptor deps + - name: Install Transeptor deps run: npm install --no-package-lock - - - name: Install Transeptor build tool deps + + - name: Install Transeptor build tool deps run: npm install --save-dev @nx/nx-linux-x64-gnu - name: Build Transeptor diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml new file mode 100644 index 0000000..66a680c --- /dev/null +++ b/.github/workflows/create-release-pr.yml @@ -0,0 +1,48 @@ +name: Create Release Pull Request + +on: + workflow_dispatch: + inputs: + base-branch: + description: "The base branch for git operations and the pull request." + default: "main" + required: true + release-version: + description: "A specific version to bump to, i.e. 0.1.1" + required: true + +env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # setting GH_TOKEN for the entire workflow + +jobs: + create-release-pr: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: 14 + + - name: Configure Git identity + run: | + git config user.email "actions@github.com" + git config user.name "GitHub Actions" + + - name: Create release branch + run: | + branch_name="release/v${{ github.event.inputs.release-version }}" + git checkout -b $branch_name + git commit --allow-empty -m "Release v${{ github.event.inputs.release-version }}" + git push origin $branch_name + + echo "::set-output name=branch_name::$branch_name" + + - name: Open Pull Request + run: | + gh pr create --base ${{ github.event.inputs.base-branch }} --head "release/v${{ github.event.inputs.release-version }}" --title "Release v${{ github.event.inputs.release-version }}" --body "Automated release PR for version v${{ github.event.inputs.release-version }}" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..1b5d900 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,64 @@ +name: Main + +on: + push: + branches: [main] + pull_request: + +jobs: + build-lint-test: + uses: ./.github/workflows/build-lint-test.yml + + compliance: + uses: ./.github/workflows/compliance.yml + + all-jobs-completed: + name: All jobs completed + runs-on: ubuntu-latest + needs: + - build-lint-test + outputs: + PASSED: ${{ steps.set-output.outputs.PASSED }} + steps: + - name: Set PASSED output + id: set-output + run: echo "PASSED=true" >> "$GITHUB_OUTPUT" + + all-jobs-pass: + name: All jobs pass + if: ${{ always() }} + runs-on: ubuntu-latest + needs: all-jobs-completed + steps: + - name: Check that all jobs have passed + run: | + passed="${{ needs.all-jobs-completed.outputs.PASSED }}" + if [[ $passed != "true" ]]; then + exit 1 + fi + + is-release: + # Filtering by `push` events ensures that we only release from the `main` branch, which is a + # requirement for our npm publishing environment. + # The commit author should always be 'github-actions' for releases created by the + # 'create-release-pr' workflow, so we filter by that as well to prevent accidentally + # triggering a release. + if: github.event_name == 'push' && startsWith(github.event.head_commit.author.name, 'github-actions') + needs: all-jobs-pass + outputs: + IS_RELEASE: ${{ steps.is-release.outputs.IS_RELEASE }} + runs-on: ubuntu-latest + steps: + - uses: MetaMask/action-is-release@v1 + id: is-release + + publish-release: + needs: is-release + if: needs.is-release.outputs.IS_RELEASE == 'true' + name: Publish Release transeptor docker image + permissions: + contents: write + uses: ./.github/workflows/publish-release.yml + secrets: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml new file mode 100644 index 0000000..836b231 --- /dev/null +++ b/.github/workflows/publish-release.yml @@ -0,0 +1,38 @@ +name: Publish Release transeptor docker image + +on: + workflow_call: + secrets: + DOCKER_USERNAME: + required: true + DOCKER_PASSWORD: + required: true + +jobs: + push_to_registry: + name: Push Docker image to Docker Hub + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v4 + + - name: Log in to Docker Hub + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Get package version + id: get_version + run: echo version=$(node -p "require('./package.json').version") >> $GITHUB_OUTPUT + + - name: Build and push Docker image + uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 + with: + context: . + platforms: linux/amd64,linux/arm64,linux/arm64/v8 + file: ./Dockerfile + push: true + tags: | + transeptorlabs/bundler:${{ steps.get_version.outputs.version }} + transeptorlabs/bundler:latest \ No newline at end of file diff --git a/README.md b/README.md index f0be91a..87421f5 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@

Node Version TypeScript - - + + codecov diff --git a/docker-image-release-notes.md b/docker-image-release-notes.md deleted file mode 100644 index 39edcd0..0000000 --- a/docker-image-release-notes.md +++ /dev/null @@ -1,18 +0,0 @@ - -## Update version -update version in package.json - -# Build Docker images -docker build -t bundler-typescript:v . - -# Log into Docker hub -docker login -u transeptorlabs - -# Rename image to remote repo name -docker tag bundler-typescript:v transeptorlabs/bundler:v -docker tag bundler-typescript:v transeptorlabs/bundler:latest - -## Push image -docker push transeptorlabs/bundler:v -docker push transeptorlabs/bundler:latest - diff --git a/package.json b/package.json index 6e17049..aa14685 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "root", + "version": "0.5.0-alpha.0", "author": { "name": "Transeptor Labs", "email": "transeptorhq@gmail.com", @@ -14,7 +15,6 @@ "bugs": { "url": "https://github.com/transeptorlabs/transeptor-bundler/issues" }, - "private": true, "scripts": { "///ab": "_____________________________________________________________________", "///cv": "________________________WELCOME BUILDERS______________________________", diff --git a/packages/bundle/src/BundleProcessor.ts b/packages/bundle/src/BundleProcessor.ts index 7553502..e953e4b 100644 --- a/packages/bundle/src/BundleProcessor.ts +++ b/packages/bundle/src/BundleProcessor.ts @@ -57,7 +57,6 @@ export class BundleProcessor { */ public async sendNextBundle(isAuto = false): Promise { if (this.mempoolManager.size() === 0) { - Logger.debug('Mempool size is 0 - no user ops to bundle') return { transactionHash: '', userOpHashes: [] @@ -69,12 +68,10 @@ export class BundleProcessor { ? await this.mempoolManager.getAllPending() : await this.mempoolManager.getNextPending() - Logger.debug(`Got entries from mempool: ${entries.length}`) const [bundle, storageMap] = await this.createBundle(entries) Logger.debug({ length: bundle.length, bundle }, 'bundle created') if (bundle.length === 0) { - Logger.debug('sendNextBundle - no bundle to send') return { transactionHash: '', userOpHashes: [] @@ -82,7 +79,6 @@ export class BundleProcessor { } else { const beneficiary = await this.selectBeneficiary() const ret = await this.sendBundle(bundle, beneficiary, storageMap) - Logger.debug(`sendNextBundle exit - after sent a bundle of ${bundle.length} `) return ret } } @@ -225,17 +221,15 @@ export class BundleProcessor { ret = await this.providerService.send('eth_sendRawTransactionConditional', [ signedTx, { knownAccounts: storageMap } ]) - Logger.debug({ret}, 'eth_sendRawTransactionConditional ret=') + Logger.debug({ret, length: userOps.length}, 'eth_sendRawTransactionConditional ret=') } else { // ret = await this.signer.sendTransaction(tx) ret = await this.providerService.send('eth_sendRawTransaction', [signedTx]) - Logger.debug({ret}, 'eth_sendRawTransaction ret=') + Logger.debug({ret, length: userOps.length}, 'eth_sendRawTransaction ret=') } // TODO: parse ret, and revert if needed. - // Logger.debug({ret}, 'ret=') - Logger.debug({length: userOps.length}, 'sent handleOps') - + // hashes are needed for debug rpc only. const hashes = await this.getUserOpHashes(userOps) return { diff --git a/packages/cli/src/Config.ts b/packages/cli/src/Config.ts index 257df40..bdd5165 100644 --- a/packages/cli/src/Config.ts +++ b/packages/cli/src/Config.ts @@ -92,10 +92,8 @@ export class Config { throw new Error('ALCHEMY_API_KEY env var not set') } - Logger.debug(`Using remote eth client at ${programOpts.network as string}`) this.provider = this.getNetworkProvider(programOpts.network as string, process.env.ALCHEMY_API_KEY as string) } else { - Logger.debug(`Using local eth client at ${programOpts.network as string}`) this.provider = this.getNetworkProvider(programOpts.network as string) } diff --git a/packages/json-rpc-handler/src/RpcMethodHandler.ts b/packages/json-rpc-handler/src/RpcMethodHandler.ts index d119ee4..ec675d4 100644 --- a/packages/json-rpc-handler/src/RpcMethodHandler.ts +++ b/packages/json-rpc-handler/src/RpcMethodHandler.ts @@ -27,8 +27,6 @@ export class RpcMethodHandler { public async doHandleRequest(request: JsonRpcRequest): Promise { try { - Logger.debug({request}, '>> Incoming request') - const isValidRpc: boolean | JsonRpcErrorResponse = this.jsonRpcRequestValidator(request) if (typeof isValidRpc !== 'boolean') { return isValidRpc @@ -38,7 +36,7 @@ export class RpcMethodHandler { const params = request.params let result: any - Logger.debug('Handling request(PASSED VALIDATION)') + Logger.debug( {method, params}, 'Handling incoming request') switch (method) { case 'eth_chainId': result = await this.providerService.getChainId() @@ -134,12 +132,6 @@ export class RpcMethodHandler { result: any ): JsonRpcSuccessResponse { const hexlifyResult = deepHexlify(result) - Logger.debug({ - jsonrpc: '2.0', - id, - result: hexlifyResult, - }, '<< Sending sucess response') - return { jsonrpc: '2.0', id, @@ -168,9 +160,7 @@ export class RpcMethodHandler { if (data) { errorResponse.error.data = data } - - Logger.debug(errorResponse, '<< Sending error response') - + return errorResponse } } \ No newline at end of file diff --git a/packages/json-rpc-handler/src/services/Eth.ts b/packages/json-rpc-handler/src/services/Eth.ts index 336bd4e..d7f4223 100644 --- a/packages/json-rpc-handler/src/services/Eth.ts +++ b/packages/json-rpc-handler/src/services/Eth.ts @@ -38,16 +38,6 @@ export class EthAPI { public async sendUserOperation(userOp: UserOperation, supportedEntryPoints: string) { await this.validateParameters(userOp, supportedEntryPoints) const userOpReady = await resolveProperties(userOp) - Logger.debug( - { - sender: userOpReady.sender, - nonce: tostr(userOpReady.nonce), - entryPoint: supportedEntryPoints, - paymaster: getAddr(userOpReady.paymasterAndData), - }, - 'Starting UserOperation validation' - ) - this.validationService.validateInputParameters(userOp, supportedEntryPoints) const validationResult = await this.validationService.validateUserOp(userOp, undefined) const userOpHash = await this.entryPointContract.getUserOpHash(userOpReady) diff --git a/packages/provider/src/ProviderService.ts b/packages/provider/src/ProviderService.ts index 4225c2e..dfa05ee 100644 --- a/packages/provider/src/ProviderService.ts +++ b/packages/provider/src/ProviderService.ts @@ -107,8 +107,7 @@ export class ProviderService { public async debug_traceCall (tx: Deferrable, options: TraceOptions): Promise { const tx1 = await resolveProperties(tx) const ret = await this.provider.send('debug_traceCall', [tx1, 'latest', options]).catch(e => { - Logger.error({error: e.message}, 'ex=') - Logger.debug({traceOptions: options.tracer?.toString().split('\n').map((line, index) => `${index + 1}: ${line}`).join('\n')}, 'tracer=') + Logger.error({error: e.message}, 'error in debug_traceCall') throw e }) return ret as BundlerCollectorReturn diff --git a/packages/reputation/src/ReputationManager.ts b/packages/reputation/src/ReputationManager.ts index 903db06..6af5497 100644 --- a/packages/reputation/src/ReputationManager.ts +++ b/packages/reputation/src/ReputationManager.ts @@ -106,7 +106,6 @@ export class ReputationManager { } const entry = this.getOrCreate(addr) entry.opsSeen++ - Logger.debug({addr, entry}, 'after seen++') } /** @@ -117,7 +116,6 @@ export class ReputationManager { public updateIncludedStatus (addr: string): void { const entry = this.getOrCreate(addr) entry.opsIncluded++ - Logger.debug({addr, entry}, 'after Included++') } public isWhitelisted (addr: string): boolean { diff --git a/packages/validation/src/ValidationService.ts b/packages/validation/src/ValidationService.ts index 83428d0..0e97824 100644 --- a/packages/validation/src/ValidationService.ts +++ b/packages/validation/src/ValidationService.ts @@ -144,21 +144,7 @@ export class ValidationService { // a real error, not a result. throw new Error(errFullName) } - Logger.debug( - { - dumpTree: JSON.stringify(tracerResult, null, 2) - .replace(new RegExp(userOp.sender.toLowerCase()), '{sender}') - .replace( - new RegExp(getAddr(userOp.paymasterAndData) ?? '--no-paymaster--'), - '{paymaster}' - ) - .replace( - new RegExp(getAddr(userOp.initCode) ?? '--no-initcode--'), - '{factory}' - ) - }, - '==dump tree=' - ) + return [errorResult, tracerResult] } catch (e: any) { // if already parsed, throw as is @@ -213,8 +199,7 @@ export class ValidationService { throw new Error('simulateValidation reverted with no revert string!') } } else { - Logger.debug('Running validation no storage or opcode checks') - // NOTE: this mode doesn't do any opcode checking and no stake checking! + Logger.debug('Running validation no stake or opcode checks') res = await this.callSimulateValidation(userOp) } diff --git a/packages/validation/src/parseScannerResult.ts b/packages/validation/src/parseScannerResult.ts index 29157f2..f3b13e1 100644 --- a/packages/validation/src/parseScannerResult.ts +++ b/packages/validation/src/parseScannerResult.ts @@ -326,16 +326,6 @@ export function parseScannerResult( return false } - Logger.debug( - { - entityTitle, - entityAddr, - k: mapOf(tracerResults.keccak, (k) => keccak256(k)), - reads, - }, - 'dump keccak calculations and reads' - ) - /* scan all slots. find a referenced slot at the end of the scan, we will check if the entity has stake, and report that slot if not.