Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 44 additions & 10 deletions .github/workflows/taiko-client--test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,48 @@ on:
branches: [main]
paths:
- "packages/taiko-client/**"
# `DeployProtocolOnL1`'s import closure reaches `contracts/`, `test/shared/` and the
# inbox mocks under `test/`, so listing only the obvious directories goes stale the
# moment someone adds an import — the same silent gap this workflow just fixed. These
# are `protocol.yml`'s own paths instead: whatever can affect the protocol build can
# affect the contracts these tests deploy. `deployments/` is excluded because
# `deploy_l1.json` is generated by the run, not read into it.
- "packages/protocol/**"
- "!packages/protocol/contract_layout_*"
- "!packages/protocol/audit/**"
- "!packages/protocol/docs/**"
- "!packages/protocol/simulation/**"
- "!packages/protocol/deployments/**"
- "!packages/protocol/script/layer2/hekla/**"
- "!packages/protocol/script/layer2/mainnet/**"
- "!packages/protocol/script/layer1/hekla/**"
- "!packages/protocol/script/layer1/mainnet/**"
- "!packages/protocol/script/layer1/preconf/**"
- "!packages/protocol/script/layer1/provers/**"
- "!packages/protocol/script/layer1/team/**"
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- "packages/taiko-client/**"
# `DeployProtocolOnL1`'s import closure reaches `contracts/`, `test/shared/` and the
# inbox mocks under `test/`, so listing only the obvious directories goes stale the
# moment someone adds an import — the same silent gap this workflow just fixed. These
# are `protocol.yml`'s own paths instead: whatever can affect the protocol build can
# affect the contracts these tests deploy. `deployments/` is excluded because
# `deploy_l1.json` is generated by the run, not read into it.
- "packages/protocol/**"
- "!packages/protocol/contract_layout_*"
- "!packages/protocol/audit/**"
- "!packages/protocol/docs/**"
- "!packages/protocol/simulation/**"
- "!packages/protocol/deployments/**"
- "!packages/protocol/script/layer2/hekla/**"
- "!packages/protocol/script/layer2/mainnet/**"
- "!packages/protocol/script/layer1/hekla/**"
- "!packages/protocol/script/layer1/mainnet/**"
- "!packages/protocol/script/layer1/preconf/**"
- "!packages/protocol/script/layer1/provers/**"
- "!packages/protocol/script/layer1/team/**"
- "go.mod"
- "go.sum"
- "!**/*.md"
Expand Down Expand Up @@ -85,7 +123,6 @@ jobs:
timeout-minutes: 30
env:
CGO_ENABLED: 1
PROTOCOL_FORK_DIR: protocol-taiko-mono

strategy:
fail-fast: false
Expand All @@ -100,13 +137,6 @@ jobs:

- uses: actions/checkout@v7

- name: Checkout protocol for testing
uses: actions/checkout@v7
with:
repository: taikoxyz/taiko-mono
path: ${{ env.PROTOCOL_FORK_DIR }}
ref: main

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

Expand Down Expand Up @@ -159,14 +189,18 @@ jobs:
with:
cache-dependency-path: pnpm-lock.yaml

# Deploy the PR's own protocol contracts: a second checkout pinned to `main`
# would test different contracts on every re-run and never exercise a PR
# that changes protocol and client together.
- name: Install pnpm dependencies for protocol
run: cd ./${{ env.PROTOCOL_FORK_DIR }}/packages/protocol && pnpm install
working-directory: packages/protocol
run: pnpm install

- name: Run Tests on ${{ matrix.execution_node }} execution engine
working-directory: packages/taiko-client
env:
L2_NODE: ${{ matrix.execution_node }}
PROTOCOL_DIR: ${{ github.workspace }}/${{ env.PROTOCOL_FORK_DIR }}/packages/protocol
PROTOCOL_DIR: ${{ github.workspace }}/packages/protocol
run: make test

- name: Codecov.io
Expand Down
38 changes: 38 additions & 0 deletions .github/workflows/taiko-client-rs--test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,48 @@ on:
branches: [main]
paths:
- "packages/taiko-client-rs/**"
# `DeployProtocolOnL1`'s import closure reaches `contracts/`, `test/shared/` and the
# inbox mocks under `test/`, so listing only the obvious directories goes stale the
# moment someone adds an import — the same silent gap this workflow just fixed. These
# are `protocol.yml`'s own paths instead: whatever can affect the protocol build can
# affect the contracts these tests deploy. `deployments/` is excluded because
# `deploy_l1.json` is generated by the run, not read into it.
- "packages/protocol/**"
- "!packages/protocol/contract_layout_*"
- "!packages/protocol/audit/**"
- "!packages/protocol/docs/**"
- "!packages/protocol/simulation/**"
- "!packages/protocol/deployments/**"
- "!packages/protocol/script/layer2/hekla/**"
- "!packages/protocol/script/layer2/mainnet/**"
- "!packages/protocol/script/layer1/hekla/**"
- "!packages/protocol/script/layer1/mainnet/**"
- "!packages/protocol/script/layer1/preconf/**"
- "!packages/protocol/script/layer1/provers/**"
- "!packages/protocol/script/layer1/team/**"
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- "packages/taiko-client-rs/**"
# `DeployProtocolOnL1`'s import closure reaches `contracts/`, `test/shared/` and the
# inbox mocks under `test/`, so listing only the obvious directories goes stale the
# moment someone adds an import — the same silent gap this workflow just fixed. These
# are `protocol.yml`'s own paths instead: whatever can affect the protocol build can
# affect the contracts these tests deploy. `deployments/` is excluded because
# `deploy_l1.json` is generated by the run, not read into it.
- "packages/protocol/**"
- "!packages/protocol/contract_layout_*"
- "!packages/protocol/audit/**"
- "!packages/protocol/docs/**"
- "!packages/protocol/simulation/**"
- "!packages/protocol/deployments/**"
- "!packages/protocol/script/layer2/hekla/**"
- "!packages/protocol/script/layer2/mainnet/**"
- "!packages/protocol/script/layer1/hekla/**"
- "!packages/protocol/script/layer1/mainnet/**"
- "!packages/protocol/script/layer1/preconf/**"
- "!packages/protocol/script/layer1/provers/**"
- "!packages/protocol/script/layer1/team/**"
- "!**/*.md"

concurrency:
Expand Down
84 changes: 84 additions & 0 deletions packages/taiko-client/bindings/encoding/input_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package encoding

import (
"fmt"
"math/big"
"testing"

"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)

// basefeeSharingPctgRange returns every value the inbox accepts: `LibInboxSetup.validateConfig`
// requires `basefeeSharingPctg <= 100`. taiko-geth splits a transaction's basefee as
// `gasUsed * baseFee * pctg / 100` to the coinbase and pays the remainder to the treasury, so at 0
// the coinbase is paid nothing and at 100 the treasury is paid nothing. Both ends are reachable
// configurations rather than edge cases, and covering all 101 values costs nothing.
func basefeeSharingPctgRange() []uint8 {
pctgs := make([]uint8, 0, 101)
for pctg := 0; pctg <= 100; pctg++ {
pctgs = append(pctgs, uint8(pctg))
}
return pctgs
}

// TestEncodeShastaExtraDataBasefeeSharingPctg round-trips every accepted percentage through the
// decoder both clients rely on, so a change at either end of the range shows up here rather than
// as a block the drivers re-derive with different extraData.
func TestEncodeShastaExtraDataBasefeeSharingPctg(t *testing.T) {
for _, pctg := range basefeeSharingPctgRange() {
t.Run(fmt.Sprintf("pctg=%d", pctg), func(t *testing.T) {
extraData, err := EncodeShastaExtraData(pctg, big.NewInt(1))
require.Nil(t, err)
require.Len(t, extraData, params.ShastaExtraDataLen)
require.Equal(t, pctg, core.DecodeShastaBasefeeSharingPctg(extraData))
})
}
}

// TestEncodeShastaExtraDataIndependentFields asserts the percentage and the proposal ID never read
// each other's bytes, including when either is zero and when the ID fills its whole uint48.
func TestEncodeShastaExtraDataIndependentFields(t *testing.T) {
maxProposalID := new(big.Int).Sub(
new(big.Int).Lsh(big.NewInt(1), uint(params.ShastaExtraDataProposalIDLength*8)),
big.NewInt(1),
)
proposalIDs := []*big.Int{big.NewInt(0), big.NewInt(1), big.NewInt(1337), maxProposalID}

for _, pctg := range basefeeSharingPctgRange() {
for _, proposalID := range proposalIDs {
t.Run(fmt.Sprintf("pctg=%d/proposalID=%s", pctg, proposalID), func(t *testing.T) {
extraData, err := EncodeShastaExtraData(pctg, proposalID)
require.Nil(t, err)

require.Equal(t, pctg, core.DecodeShastaBasefeeSharingPctg(extraData))

decodedID, err := core.DecodeShastaProposalID(extraData)
require.Nil(t, err)
require.Zero(t, proposalID.Cmp(decodedID))
})
}
}
}

// TestEncodeShastaExtraDataRejectsInvalidProposalID pins the three cases the encoder refuses, so an
// out-of-range proposal ID never silently truncates into the percentage byte.
func TestEncodeShastaExtraDataRejectsInvalidProposalID(t *testing.T) {
tooLarge := new(big.Int).Lsh(big.NewInt(1), uint(params.ShastaExtraDataProposalIDLength*8))

for _, tt := range []struct {
name string
proposalID *big.Int
wantErr string
}{
{"nil", nil, "proposal ID is nil"},
{"negative", big.NewInt(-1), "proposal ID is negative"},
{"tooLarge", tooLarge, "proposal ID too large"},
} {
t.Run(tt.name, func(t *testing.T) {
_, err := EncodeShastaExtraData(100, tt.proposalID)
require.ErrorContains(t, err, tt.wantErr)
})
}
}
Loading