Skip to content
Open
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
5 changes: 5 additions & 0 deletions build/checksums.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ e94732c94f149690aa0ab11c26090577211b4a988137cb2c03ec0b54e750402e go1.25.1.plan9
1261dfad7c4953c0ab90381bc1242dc54e394db7485c59349428d532b2273343 go1.25.1.solaris-amd64.tar.gz
04bc3c078e9e904c4d58d6ac2532a5bdd402bd36a9ff0b5949b3c5e6006a05ee go1.25.1.windows-arm64.zip

# version:tamago 1.25.6
# https://github.com/usbarmory/tamago-go/releases/download/tamago-go1.25.6/
fbab70549e5977150d9095829608b5b8c7a6226930f91beb8edd614f2a71348e tamago-go1.25.6.linux-amd64.tar.gz
8bfc5a4f2ff54625c3a26a1b8749a6639d9f85dbd2f687c41c932517c0814368 tamago-go1.25.6.linux-armv7l.tar.gz

# version:golangci 2.4.0
# https://github.com/golangci/golangci-lint/releases/
# https://github.com/golangci/golangci-lint/releases/download/v2.4.0/
Expand Down
70 changes: 67 additions & 3 deletions build/ci.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ var (
Tags: "ziren",
Env: map[string]string{"GOMIPS": "softfloat", "CGO_ENABLED": "0"},
},
{
Name: "zisk",
GOOS: "tamago",
GOARCH: "riscv64",
Tags: "tamago,zisk",
Env: map[string]string{"CGO_ENABLED": "0", "GO_EXTLINK_ENABLED": "0"},
},
{
Name: "wasm-js",
GOOS: "js",
Expand Down Expand Up @@ -281,16 +288,37 @@ func doInstallKeeper(cmdline []string) {
flag.CommandLine.Parse(cmdline)
env := build.Env()

// Configure the toolchain.
var (
csdb *download.ChecksumDB
tamagoRoot string
)
tc := build.GoToolchain{}
if *dlgo {
csdb := download.MustLoadChecksums("build/checksums.txt")
tc.Root = build.DownloadGo(csdb)
csdb = download.MustLoadChecksums("build/checksums.txt")
}

for _, target := range keeperTargets {
log.Printf("Building keeper-%s", target.Name)

// Configure the toolchain.
if target.Name == "tamago" {
if runtime.GOOS != "linux" {
log.Printf("Skipping keeper-%s (tamago builds are only supported on linux hosts)", target.Name)
continue
}
if !*dlgo {
log.Printf("Skipping keeper-%s (tamago build requires -dlgo)", target.Name)
continue
}

if tamagoRoot == "" {
tamagoRoot = downloadTamago(csdb)
}
tc.Root = tamagoRoot
} else if *dlgo {
tc.Root = build.DownloadGo(csdb)
}

// Configure the build.
tc.GOARCH = target.GOARCH
tc.GOOS = target.GOOS
Expand Down Expand Up @@ -447,6 +475,42 @@ func downloadSpecTestFixtures(csdb *download.ChecksumDB, cachedir string) string
return filepath.Join(cachedir, base)
}

// downloadTamago downloads the tamago-go toolchain and returns its GOROOT.
func downloadTamago(csdb *download.ChecksumDB) string {
version, err := csdb.FindVersion("tamago")
if err != nil {
log.Fatal(err)
}
if runtime.GOOS != "linux" {
log.Printf("Skipping tamago toolchain download (unsupported host os: %s)", runtime.GOOS)
return ""
}
arch := runtime.GOARCH
if arch == "arm" {
arch = "armv7l"
}
file := fmt.Sprintf("tamago-go%s.%s-%s.tar.gz", version, runtime.GOOS, arch)

ucache, err := os.UserCacheDir()
if err != nil {
log.Fatal(err)
}
dst := filepath.Join(ucache, file)
if err := csdb.DownloadFileFromKnownURL(dst); err != nil {
log.Fatal(err)
}

toolRoot := filepath.Join(ucache, fmt.Sprintf("geth-tamago-go-%s-%s-%s", version, runtime.GOOS, arch))
if err := build.ExtractArchive(dst, toolRoot); err != nil {
log.Fatal(err)
}
goroot, err := filepath.Abs(filepath.Join(toolRoot, "go"))
if err != nil {
log.Fatal(err)
}
return goroot
}

// doCheckGenerate ensures that re-generating generated files does not cause
// any mutations in the source file tree.
func doCheckGenerate() {
Expand Down
3 changes: 3 additions & 0 deletions cmd/keeper/dummy_fastcache/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/ethereum/go-ethereum/cmd/keeper/dummy_fastcache

go 1.24.0
13 changes: 13 additions & 0 deletions cmd/keeper/dummy_fastcache/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package fastcache

type Cache struct{}

func (*Cache) Get(dst, k []byte) []byte { return nil }
func (*Cache) HasGet(dst, k []byte) ([]byte, bool) { return nil, false }
func (*Cache) Set(k, v []byte) {}
func (*Cache) Reset() {}
func (*Cache) Del([]byte) {}

func New(int) *Cache {
return &Cache{}
}
32 changes: 32 additions & 0 deletions cmd/keeper/getpayload_zisk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2026 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

//go:build zisk

package main

import (
"unsafe"

"github.com/ethereum/go-ethereum/cmd/keeper/zisk"
)

func getInput() []byte {
inputPtr := unsafe.Pointer(uintptr(zisk.INPUT_ADDR + 8))
inputSize := *(*uint64)(inputPtr)
inputDataPtr := unsafe.Pointer(uintptr(zisk.INPUT_ADDR + 16))
return unsafe.Slice((*byte)(inputDataPtr), int(inputSize))
}
5 changes: 3 additions & 2 deletions cmd/keeper/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/ethereum/go-ethereum/cmd/keeper

go 1.24.0
go 1.25.6

require (
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6
Expand All @@ -11,7 +11,6 @@ require (
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/VictoriaMetrics/fastcache v1.13.0 // indirect
github.com/bits-and-blooms/bitset v1.20.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/consensys/gnark-crypto v0.18.1 // indirect
github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
Expand Down Expand Up @@ -39,3 +38,5 @@ require (
)

replace github.com/ethereum/go-ethereum => ../../

replace github.com/VictoriaMetrics/fastcache => ./dummy_fastcache
4 changes: 0 additions & 4 deletions cmd/keeper/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0=
github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU=
Expand Down
4 changes: 2 additions & 2 deletions cmd/keeper/stubs.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

//go:build !example && !ziren && !wasm
// +build !example,!ziren,!wasm
//go:build !example && !ziren && !wasm && !zisk
// +build !example,!ziren,!wasm,!zisk

package main

Expand Down
24 changes: 24 additions & 0 deletions cmd/keeper/tamago_board.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2025 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

//go:build tamago
// +build tamago

package main

import (
_ "github.com/ethereum/go-ethereum/cmd/keeper/zisk"
)
106 changes: 106 additions & 0 deletions cmd/keeper/zisk/board.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright 2026 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

//go:build tamago && riscv64

package zisk

import (
"unsafe"
)

const (
// ZisK I/O addresses
INPUT_ADDR = 0x90000000
QEMU_EXIT_ADDR = 0x100000
QEMU_EXIT_CODE = 0x5555
OUTPUT_ADDR = 0xa001_0000
UART_ADDR = 0xa000_0200
ARCH_ID_ZISK = 0xFFFEEEE // TEMPORARY // TODO register one
MAX_INPUT = 0x2000
MAX_OUTPUT = 0x1_0000
)

var outputCount uint32 = 0

//go:linkname ramStart runtime.ramStart
var ramStart uint64 = 0xa0020000 // Match ZisK's RAM location

//go:linkname ramSize runtime.ramSize
var ramSize uint64 = 0x1FFE0000 // Match ZisK's RAM size (~512MB)

// ramStackOffset is always defined here as there's no linkramstackoffset build tag
//
//go:linkname ramStackOffset runtime.ramStackOffset
var ramStackOffset uint64 = 0x100000 // 1MB stack (matching ZisK)

// Bloc sets the heap start address to bypass initBloc()
//
//go:linkname Bloc runtime.Bloc
var Bloc uintptr = 0xa0100000 // Start heap after stack (ramStart + ramStackOffset)

// printk implementation for zkVM
//
//go:linkname printk runtime.printk
func printk(c byte) {
// TODO: This is a stub. Just write to the output address
// Write directly to OUTPUT_ADDR
// Format: [count:u32][data:bytes]
// First update the count at OUTPUT_ADDR
outputCount++
*(*uint32)(unsafe.Pointer(uintptr(OUTPUT_ADDR))) = outputCount

// Write the byte at OUTPUT_ADDR + 4 + (outputCount-1)
*(*byte)(unsafe.Pointer(uintptr(OUTPUT_ADDR + 4 + outputCount - 1))) = c
}

// hwinit1 is now defined in hwinit1.s
// we use it to set A0/A1 registers to the input and output address

// Use this as a stub timer. It is all single threaded, and there is no concept of time.
// This may return the cycle count in the future.
var timer int64 = 0

//go:linkname nanotime1 runtime.nanotime1
func nanotime1() int64 {
// Return deterministic time for zkVM
// Could be based on instruction count or fixed increments
timer++
return timer * 1000
}

//go:linkname initRNG runtime.initRNG
func initRNG() {
// Deterministic RNG initialization
// TODO: There is no "proper" rng so nothing to init.
}

//go:linkname getRandomData runtime.getRandomData
func getRandomData(b []byte) {
// Deterministic "random" data
// In a real zkVM, this might come from the input
for i := range b {
b[i] = byte(i & 0xFF)
}
}

// Init initializes the zkVM board
func Init() {
timer = 0
}

// Shutdown is defined in shutdown.s and uses ecall to exit
func Shutdown()
18 changes: 18 additions & 0 deletions cmd/keeper/zisk/cpu_riscv64.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//go:build tamago && riscv64

#include "textflag.h"

// Entry point - this is where execution starts
TEXT cpuinit(SB),NOSPLIT|NOFRAME,$0
// Clear A0/A1 registers so runtime does not think we have
// argc/argv arguments
MOV $0, A0
MOV $0, A1
// Jump to tamago runtime for RISC-V
JMP runtime·rt0_riscv64_tamago(SB)

// hwinit0 is called by the runtime during initialization
TEXT runtime·hwinit0(SB),NOSPLIT|NOFRAME,$0
// Hardware initialization before runtime setup
// For zkVM, nothing special needed here
RET
17 changes: 17 additions & 0 deletions cmd/keeper/zisk/hwinit1.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//go:build tamago && riscv64

#include "textflag.h"

#define INPUT_ADDR 0x90000000
#define OUTPUT_ADDR 0xa0010000

// hwinit1 is called after basic runtime initialization
// We set A0/A1 here instead of in the emulator
TEXT runtime·hwinit1(SB),NOSPLIT|NOFRAME,$0
// Set A0 to INPUT_ADDR
MOV $INPUT_ADDR, A0

// Set A1 to OUTPUT_ADDR
MOV $OUTPUT_ADDR, A1

RET
24 changes: 24 additions & 0 deletions cmd/keeper/zisk/shutdown.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//go:build tamago && riscv64 && zisk

#include "textflag.h"

#define ARCH_ID_ZISK 0xFFFEEEE
#define QEMU_EXIT_ADDR 0x100000
#define QEMU_EXIT_CODE 0x5555

// Shutdown triggers ZisK exit via ecall with a7=93
TEXT ·Shutdown(SB),NOSPLIT|NOFRAME,$0
// Read marchid CSR into A0 (CSRRS x10, 0xF12, x0)
WORD $0xF1202573
MOV $ARCH_ID_ZISK, A1 // Load ZisK arch ID
BNE A0, A1, qemu_exit // If not, jump to qemu_exit

MOV $93, A7 // CAUSE_EXIT = 93
ECALL // System call to exit
RET // Should never reach here

qemu_exit:
MOV $QEMU_EXIT_CODE, T0 // Load the exit code for QEMU
MOV $QEMU_EXIT_ADDR, T1 // Load the exit address for QEMU
ECALL // System call to exit QEMU
RET // Should never reach here
Loading
Loading