Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
fcfc468
Ethereum Oracle
ezeike Jul 23, 2025
52bb640
Increased max net address length
ezeike Dec 13, 2025
20c85e7
🐛 fix: add embed directives and respect wss scheme for secure connect…
ezeike Dec 17, 2025
0b0b965
🔊 feat: format oracle log output with hex-encoded byte fields
ezeike Dec 17, 2025
002c8c6
Optimized Dockerfile
ezeike Dec 17, 2025
7ab9629
🔊 feat: add logging for websocket connection lifecycle events
ezeike Dec 19, 2025
7b6de96
📈 feat: add comprehensive oracle metrics for observability
ezeike Dec 19, 2025
4daed67
📈 feat: add comprehensive Eth block provider metrics
ezeike Dec 19, 2025
294c34f
📈 feat: add block height metrics to eth block provider
ezeike Dec 19, 2025
1c88a00
📝 docs: add comprehensive oracle metrics documentation
ezeike Dec 19, 2025
5e62965
🎨 style: fix formatting and trailing newlines
ezeike Dec 19, 2025
9d1385b
Oracle nil fix
ezeike Dec 22, 2025
0e107d5
log updates
ezeike Dec 22, 2025
dacf6c8
🔊 feat: promote safe height check log to info level
ezeike Dec 22, 2025
5edc4f5
Logging updates
ezeike Dec 23, 2025
7b70e16
log updates
ezeike Dec 23, 2025
ac8f7cf
🔊 feat: improve order hold logging with specific reasons at info level
ezeike Dec 23, 2025
13f0204
git diff cleanup
andrewnguyen22 Dec 25, 2025
a0640fd
patch for warning
andrewnguyen22 Dec 25, 2025
ac6a5d5
🚚 refactor: rename CanopyOrders endpoint to OracleOrders
ezeike Jan 3, 2026
a149dcc
Merge branch 'main' into eth-oracle
andrewnguyen22 Feb 8, 2026
80a14ce
Merge pull request #297 from canopy-network/main
andrewnguyen22 Feb 9, 2026
886a105
Merge pull request #299 from canopy-network/dev
andrewnguyen22 Feb 9, 2026
93a5d94
Merge pull request #302 from canopy-network/eth-oracle-dev
andrewnguyen22 Feb 11, 2026
5b4f820
Merge branch 'main' into eth-oracle-dev
andrewnguyen22 Feb 12, 2026
8298d7f
Merge pull request #305 from canopy-network/eth-oracle-dev
andrewnguyen22 Feb 12, 2026
27ae342
Uncomment explorer and wallet build in Dockerfile
andrewnguyen22 Feb 24, 2026
e2679df
Handle expired orderbook locks via reset orders safely
andrewnguyen22 Feb 27, 2026
ea1d93f
Fix root-chain committee swap gating and update ApplyBlock snapshot
andrewnguyen22 Feb 27, 2026
6f6f5f6
oracle: address ORA-F-004/006/007/008/013/014/015/016 findings
andrewnguyen22 Feb 27, 2026
d80fc91
fix dex price e6 overflow with bigint math
andrewnguyen22 Feb 27, 2026
8689063
fsm: return dex batch errors in certificate handling
andrewnguyen22 Feb 27, 2026
b4142b7
Merge remote-tracking branch 'origin/main' into dev
andrewnguyen22 Mar 4, 2026
ffc1d93
Merge remote-tracking branch 'origin/main' into dev
andrewnguyen22 Mar 4, 2026
3ee3662
Merge branch 'main' into dev
andrewnguyen22 Mar 5, 2026
a65f25f
Isolate auto-update release streams
andrewnguyen22 Mar 23, 2026
7946852
Merge branch 'main' into dev
andrewnguyen22 Mar 25, 2026
4367f8f
revert: remove oracle functionality from dev
andrewnguyen22 Mar 25, 2026
bd23b4b
Merge branch 'main' into dev
rem1niscence Mar 25, 2026
3875bcb
fix: various qa fixes
pablocampogo Mar 26, 2026
25eacab
fix: explorer analytics miscalculations
rem1niscence Mar 26, 2026
12aa790
fix: analytics charts use per-block counts, even grouping, and proper…
rem1niscence Mar 26, 2026
aedf2ee
fix: normalize analytics charts per block and use block-based filters
rem1niscence Mar 26, 2026
d2986e4
fix: supply view and broken nav
pablocampogo Mar 26, 2026
ae5741b
fix: transaction types chart counts distinct types not raw tx counts
rem1niscence Mar 26, 2026
17c6b09
Merge branch 'qa-wallet-explorer' into fix/explorer-analytics
rem1niscence Mar 26, 2026
aa284ac
fix: use raw messageType for transaction types, move avg fee to chain…
rem1niscence Mar 26, 2026
1c08f3f
fix: transaction page redesign
pablocampogo Mar 26, 2026
6961689
fix: missing dropdowns and fix error parsing
pablocampogo Mar 30, 2026
dfcfff5
feat: add dropdown of select address in orders view
pablocampogo Mar 31, 2026
a54b94b
Merge branch 'main' of github.com:canopy-network/canopy into qa-walle…
pablocampogo Apr 2, 2026
d8864b5
feat: make orders screen simpler
pablocampogo Apr 2, 2026
79fb497
Simplify indexer blobs delta API
andrewnguyen22 Apr 6, 2026
a5ec5a3
rpc: retain only latest full indexer snapshot
andrewnguyen22 Apr 7, 2026
5a0f6f9
ci: update Go version to 1.24 to match go.mod
andrewnguyen22 Apr 8, 2026
3249fd5
ci: include go.mod, go.sum, and workflow paths in push trigger
andrewnguyen22 Apr 8, 2026
d45d2be
ci: exclude cmd/auto-update from test suite
andrewnguyen22 Apr 8, 2026
e5f59a0
fix: more qa fixes and make code more resistant to intermitent failures
pablocampogo Apr 14, 2026
492ba3c
chore: get style more similar to launchpad
pablocampogo Apr 14, 2026
4efec54
chore: make wallet font singular and the same as explorer and launchpad
pablocampogo Apr 14, 2026
eb3d6f6
chore: eliminate gradient and bolding in wallet
pablocampogo Apr 14, 2026
38ae214
chore: more style changes
pablocampogo Apr 15, 2026
86594b6
chore: make colors and fonts more constant and create ticket feature
pablocampogo Apr 16, 2026
03afba2
chore: change row of liquid accounts to not be gray
pablocampogo Apr 17, 2026
58e26f3
fix: functionality issues on wallet and ui lies in the explorer
pablocampogo Apr 17, 2026
8e3ffae
chore: eliminate hard coded values from the wallet
pablocampogo Apr 17, 2026
f86461a
fix: delete hardcoded values from explorer and fix some minor issues
pablocampogo Apr 20, 2026
7bf4e5a
wallet: recover local web wallet changes
andrewnguyen22 Apr 21, 2026
7de5975
Merge branch 'temp/stashed-wallet-dev-merge' into dev
andrewnguyen22 Apr 21, 2026
68cbf6d
wallet: add liquid address actions to node management
andrewnguyen22 Apr 21, 2026
eb25b6d
Update explorer and wallet UI
andrewnguyen22 Apr 21, 2026
01a8f64
Merge branch 'dev' into qa-wallet-explorer
andrewnguyen22 Apr 21, 2026
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
78 changes: 78 additions & 0 deletions .docker/Dockerfile.optimized
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# syntax=docker/dockerfile:1

FROM golang:1.24.0-alpine AS builder

# Install build dependencies
RUN apk update && apk add --no-cache make bash nodejs npm git

ARG EXPLORER_BASE_PATH
ARG WALLET_BASE_PATH

WORKDIR /go/src/github.com/canopy-network/canopy

# ============================================
# OPTIMIZATION 1: Cache Go module dependencies
# Copy only go.mod and go.sum first to cache dependencies layer
# This layer only invalidates when dependencies change
# ============================================
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
go mod download

# ============================================
# OPTIMIZATION 2: Cache NPM dependencies for wallet
# Copy only package.json files first to cache npm install layer
# ============================================
COPY cmd/rpc/web/wallet/package*.json ./cmd/rpc/web/wallet/
RUN --mount=type=cache,target=/root/.npm \
npm install --prefix ./cmd/rpc/web/wallet

# ============================================
# OPTIMIZATION 3: Cache NPM dependencies for explorer
# ============================================
COPY cmd/rpc/web/explorer/package*.json ./cmd/rpc/web/explorer/
RUN --mount=type=cache,target=/root/.npm \
npm install --prefix ./cmd/rpc/web/explorer

# ============================================
# OPTIMIZATION 4: Copy web source and build BEFORE copying all source
# This caches web builds - only invalidates when web files change
# ============================================
COPY cmd/rpc/web/wallet/ ./cmd/rpc/web/wallet/
COPY cmd/rpc/web/explorer/ ./cmd/rpc/web/explorer/

ENV EXPLORER_BASE_PATH=${EXPLORER_BASE_PATH}
ENV WALLET_BASE_PATH=${WALLET_BASE_PATH}

# Build web assets (cached unless web source changes)
RUN --mount=type=cache,target=/root/.npm \
npm run build --prefix ./cmd/rpc/web/wallet
RUN --mount=type=cache,target=/root/.npm \
npm run build --prefix ./cmd/rpc/web/explorer

# ============================================
# OPTIMIZATION 5: Copy remaining source code
# Web builds are already cached above
# ============================================
COPY . .

# ============================================
# OPTIMIZATION 6: Use build cache mounts for Go
# Preserves Go build cache and module cache between builds
# This can speed up rebuilds by 5-10x
# ============================================
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg/mod \
go build -a -o bin ./cmd/main/...

# ============================================
# Final stage - minimal runtime image
# ============================================
FROM alpine:3.19

WORKDIR /app

# Copy only the built binary (web assets are embedded)
COPY --from=builder /go/src/github.com/canopy-network/canopy/bin ./bin

ENTRYPOINT ["/app/bin"]
9 changes: 6 additions & 3 deletions .github/workflows/build-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ on:
- staging
paths:
- '**.go'
- 'go.mod'
- 'go.sum'
- '.github/workflows/**'
jobs:
build:
name: Build
Expand All @@ -20,7 +23,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.21
go-version: 1.24
- name: Checkout code
uses: actions/checkout@v4
- name: Build Services
Expand All @@ -32,7 +35,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: 1.21
go-version: 1.24
- name: Checkout code
uses: actions/checkout@v4
- name: Set up cache
Expand All @@ -45,4 +48,4 @@ jobs:
restore-keys: |
${{ runner.os }}-go-
- name: Run Unit tests
run: make build/canopy-full && go test ./...
run: make build/canopy-full && go test $(go list ./... | grep -v cmd/auto-update)
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,6 @@ vendor
cmd/web/explorer/.idea
**/.DS_Store
/cmd/tps/data

rag
node_modules
3 changes: 3 additions & 0 deletions .projectile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-/node_modules
-/rag
-rag
1 change: 1 addition & 0 deletions cache/solidity-files-cache.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"_format":"","paths":{"artifacts":"out","build_infos":"out/build-info","sources":"src","tests":"test","scripts":"script","libraries":["lib","node_modules"]},"files":{"cmd/rpc/oracle/testing/contracts/USDC.sol":{"lastModificationDate":1752574865334,"contentHash":"f3edf42ae79e8f47","interfaceReprHash":null,"sourceName":"cmd/rpc/oracle/testing/contracts/USDC.sol","imports":[],"versionRequirement":"^0.8.0","artifacts":{"USDC":{"0.8.20":{"default":{"path":"USDC.sol/USDC.json","build_id":"bea85887a954e3be"}}}},"seenByCompiler":true}},"builds":["bea85887a954e3be"],"profiles":{"default":{"solc":{"optimizer":{"enabled":false,"runs":200},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"]}},"evmVersion":"cancun","viaIR":false,"libraries":{}},"vyper":{"evmVersion":"cancun","outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode"]}}}}},"preprocessed":false,"mocks":[]}
42 changes: 27 additions & 15 deletions cmd/auto-update/releaser.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ import (
"golang.org/x/mod/semver"
)

var githubAPIBaseURL = "https://api.github.com"

// GithubRelease represents a GitHub release with the used metadata
type GithubRelease struct {
TagName string `json:"tag_name"`
Assets []struct {
TagName string `json:"tag_name"`
Draft bool `json:"draft"`
Prerelease bool `json:"prerelease"`
Assets []struct {
Name string `json:"name"`
BrowserDownloadURL string `json:"browser_download_url"`
} `json:"assets"`
Expand Down Expand Up @@ -104,9 +108,11 @@ func (rm *ReleaseManager) Check() (*Release, error) {

// GetLatestRelease returns the latest release from the GitHub API
func (rm *ReleaseManager) GetLatestRelease() (*Release, error) {
// build the URL: https://api.github.com/repos/<owner>/<repo>/releases/latest
apiURL, err := url.JoinPath("https://api.github.com", "repos",
rm.config.RepoOwner, rm.config.RepoName, "releases", "latest")
// Query the releases list and select the newest release that contains the
// expected asset. This keeps CLI and plugin streams isolated even when a
// repository publishes both kinds of releases.
apiURL, err := url.JoinPath(githubAPIBaseURL, "repos",
rm.config.RepoOwner, rm.config.RepoName, "releases")
if err != nil {
return nil, err
}
Expand All @@ -130,23 +136,29 @@ func (rm *ReleaseManager) GetLatestRelease() (*Release, error) {
return nil, fmt.Errorf("unexpected status code %d", resp.StatusCode)
}
// parse the response
var rel GithubRelease
if err := json.NewDecoder(resp.Body).Decode(&rel); err != nil {
var releases []GithubRelease
if err := json.NewDecoder(resp.Body).Decode(&releases); err != nil {
return nil, err
}
// find matching asset
// find the first non-draft, non-prerelease with a matching asset. GitHub
// returns releases ordered from newest to oldest.
targetName := rm.getAssetName()
for _, asset := range rel.Assets {
if asset.Name == targetName {
return &Release{
Version: rel.TagName,
DownloadURL: asset.BrowserDownloadURL,
}, nil
for _, rel := range releases {
if rel.Draft || rel.Prerelease {
continue
}
for _, asset := range rel.Assets {
if asset.Name == targetName {
return &Release{
Version: rel.TagName,
DownloadURL: asset.BrowserDownloadURL,
}, nil
}
}
}
// return based on tagName
if rm.config.Type == ReleaseTypeCLI {
return nil, fmt.Errorf("unsupported architecture: %s-%s", runtime.GOOS, runtime.GOARCH)
return nil, fmt.Errorf("no matching asset found for CLI (looking for %s)", targetName)
}
return nil, fmt.Errorf("no matching asset found for plugin (looking for %s)", targetName)
}
Expand Down
103 changes: 103 additions & 0 deletions cmd/auto-update/releaser_stream_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package main

import (
"fmt"
"net/http"
"net/http/httptest"
"runtime"
"testing"

"github.com/stretchr/testify/require"
)

func TestGetLatestPluginReleaseFiltersByPluginAssetStream(t *testing.T) {
previousBaseURL := githubAPIBaseURL
t.Cleanup(func() {
githubAPIBaseURL = previousBaseURL
})

assetName := "go-plugin-" + runtime.GOOS + "-" + runtime.GOARCH + ".tar.gz"

server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/repos/my-org/my-plugin-repo/releases", r.URL.Path)
_, _ = w.Write([]byte(fmt.Sprintf(`[
{
"tag_name": "v9.9.9",
"assets": [{"name": "cli-linux-amd64", "browser_download_url": "https://example.com/cli"}],
"draft": false,
"prerelease": false
},
{
"tag_name": "plugin-go-v2026.78.100",
"assets": [{"name": "%s", "browser_download_url": "https://example.com/go-old"}],
"draft": false,
"prerelease": false
},
{
"tag_name": "plugin-go-v2026.79.200",
"assets": [{"name": "%s", "browser_download_url": "https://example.com/go-new"}],
"draft": false,
"prerelease": false
}
]`, assetName, assetName)))
}))
defer server.Close()

githubAPIBaseURL = server.URL

rm := NewReleaseManager(&ReleaseManagerConfig{
Type: ReleaseTypePlugin,
RepoOwner: "my-org",
RepoName: "my-plugin-repo",
PluginDir: "plugin/go",
PluginConfig: &PluginReleaseConfig{
AssetName: "go-plugin-%s-%s.tar.gz",
ArchSpecific: true,
},
}, "v0.0.0", true)

release, err := rm.GetLatestRelease()
require.NoError(t, err)
require.Equal(t, "plugin-go-v2026.78.100", release.Version)
require.Equal(t, "https://example.com/go-old", release.DownloadURL)
}

func TestGetLatestCLIReleaseIgnoresPluginOnlyReleases(t *testing.T) {
previousBaseURL := githubAPIBaseURL
t.Cleanup(func() {
githubAPIBaseURL = previousBaseURL
})

server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/repos/canopy-network/canopy/releases", r.URL.Path)
_, _ = w.Write([]byte(`[
{
"tag_name": "plugin-go-v2026.82.1774298104",
"assets": [{"name": "go-plugin-linux-amd64.tar.gz", "browser_download_url": "https://example.com/plugin"}],
"draft": false,
"prerelease": false
},
{
"tag_name": "v0.1.18+beta",
"assets": [{"name": "cli-linux-amd64", "browser_download_url": "https://example.com/cli"}],
"draft": false,
"prerelease": false
}
]`))
}))
defer server.Close()

githubAPIBaseURL = server.URL

rm := NewReleaseManager(&ReleaseManagerConfig{
Type: ReleaseTypeCLI,
RepoOwner: "canopy-network",
RepoName: "canopy",
}, "v0.1.17", true)

release, err := rm.GetLatestRelease()
require.NoError(t, err)
require.Equal(t, "v0.1.18+beta", release.Version)
require.Equal(t, "https://example.com/cli", release.DownloadURL)
}

82 changes: 82 additions & 0 deletions cmd/auto-update/releaser_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package main

import (
"fmt"
"net/http"
"net/http/httptest"
"runtime"
"testing"

"github.com/stretchr/testify/require"
)

func TestGetLatestPluginReleaseFiltersByPluginStream(t *testing.T) {
previousBaseURL := githubAPIBaseURL
t.Cleanup(func() {
githubAPIBaseURL = previousBaseURL
})

assetName := "go-plugin-" + runtime.GOOS + "-" + runtime.GOARCH + ".tar.gz"

server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/repos/my-org/my-plugin-repo/releases", r.URL.Path)
_, _ = w.Write([]byte(fmt.Sprintf(`[
{
"tag_name": "v9.9.9",
"assets": [{"name": "cli-linux-amd64", "browser_download_url": "https://example.com/cli"}],
"draft": false,
"prerelease": false
},
{
"tag_name": "plugin-python-v3.4.5",
"assets": [{"name": "python-plugin.tar.gz", "browser_download_url": "https://example.com/python"}],
"draft": false,
"prerelease": false
},
{
"tag_name": "plugin-go-v2026.78.100",
"assets": [{"name": "%s", "browser_download_url": "https://example.com/go-old"}],
"draft": false,
"prerelease": false
},
{
"tag_name": "plugin-go-v2026.79.200",
"assets": [{"name": "%s", "browser_download_url": "https://example.com/go-new"}],
"draft": false,
"prerelease": false
}
]`, assetName, assetName)))
}))
defer server.Close()

githubAPIBaseURL = server.URL

rm := NewReleaseManager(&ReleaseManagerConfig{
Type: ReleaseTypePlugin,
RepoOwner: "my-org",
RepoName: "my-plugin-repo",
PluginDir: "plugin/go",
PluginConfig: &PluginReleaseConfig{
AssetName: "go-plugin-%s-%s.tar.gz",
ArchSpecific: true,
},
}, "v0.0.0", true)

release, err := rm.GetLatestRelease()
require.NoError(t, err)
require.Equal(t, "plugin-go-v2026.79.200", release.Version)
require.Equal(t, "https://example.com/go-new", release.DownloadURL)
}

func TestShouldUpdateAcceptsPluginPrefixedSemver(t *testing.T) {
rm := NewReleaseManager(&ReleaseManagerConfig{
Type: ReleaseTypePlugin,
PluginDir: "plugin/go",
}, "v2026.78.100", true)

release := &Release{Version: "plugin-go-v2026.79.200"}
err := rm.ShouldUpdate(release)
require.NoError(t, err)
require.True(t, release.ShouldUpdate)
require.Equal(t, "v2026.79.200", release.Version)
}
Loading