Skip to content

Instantly share code, notes, and snippets.

@franciscoaguirre
Last active February 8, 2025 23:03
Show Gist options
  • Select an option

  • Save franciscoaguirre/4b00b23cb08f1e1f44b9c0c3edf3fc14 to your computer and use it in GitHub Desktop.

Select an option

Save franciscoaguirre/4b00b23cb08f1e1f44b9c0c3edf3fc14 to your computer and use it in GitHub Desktop.
JAM Test Service
%stack_size = 4096
// Can't test the "designate" host function because
// we'd need 336 * 1023 zeroes here for correct decoding.
%rw_data_size = 12
%rw_data = 00 00 00 00 00 00 00 00 00 00 00 00
// ===== JAM entrypoints =====
jump @is_authorized
fallthrough
fallthrough
fallthrough
jump @refine
fallthrough
fallthrough
fallthrough
jump @accumulate
fallthrough
fallthrough
fallthrough
jump @on_transfer
fallthrough
fallthrough
fallthrough
// ===== For testing host functions =====
jump @gas_host_fn
jump @lookup_host_fn
jump @read_host_fn
jump @write_host_fn
jump @info_host_fn
jump @bless_host_fn
jump @assign_host_fn
jump @designate_host_fn
jump @checkpoint_host_fn
jump @new_host_fn
jump @upgrade_host_fn
jump @transfer_host_fn
jump @eject_host_fn
jump @query_host_fn
jump @solicit_host_fn
jump @forget_host_fn
jump @yield_host_fn
jump @historical_lookup_host_fn
jump @fetch_host_fn
jump @export_host_fn
jump @machine_host_fn
jump @peek_host_fn
jump @poke_host_fn
jump @zero_host_fn
jump @void_host_fn
jump @invoke_host_fn
pub @is_authorized:
a1 = 0
trap
pub @refine:
a1 = 0
trap
pub @accumulate:
// Counter
a1 = 0
// Accumulator
a2 = 0
@target:
// Fetch
a3 = u8 [a1 + 0xfeff0003]
// Accumulate
a2 = a2 + a3
// Increase counter
a1 = a1 + 1
// Condition
jump @target if a1 <u 4
// Change state
u8 [0xfeff0010] = 3
a1 = 1224
a2 = 2335
a3 = 3446
a4 = 4557
// 'write' host function
ecalli 3
// Return
a0 = a2
trap
pub @on_transfer:
a1 = 0
trap
// Tests the "gas" host function.
pub @gas_host_fn:
// Call "gas" host function.
ecalli 0
trap
// Tests the "lookup" host function.
pub @lookup_host_fn:
// Call "lookup" host function.
ecalli 1
trap
// Tests the "read" host function.
pub @read_host_fn:
// Call "read" host function.
ecalli 2
trap
// Tests the "write" host function.
pub @write_host_fn:
// Write "key" in read-write memory.
u8 [0x00020000] = 107
u8 [0x00020001] = 101
u8 [0x00020002] = 121
// Pointer and length to "key".
a0 = 0x00020000
a1 = 3
// Write value in read-write memory. Just some number.
u32 [0x00020003] = 1224
a2 = 0x00020003
a3 = 4
// Call "write" host function.
ecalli 3
trap
// Tests the "info" host function.
pub @info_host_fn:
// Set service index in w7.
a0 = 0
// Set the memory address.
a1 = 0x00020004
// Call "info" host function.
ecalli 4
// Now we can get the data from memory and put it in storage.
// Key for the data
u8 [0x00020000] = 105
u8 [0x00020001] = 110
u8 [0x00020002] = 102
u8 [0x00020003] = 111
// Pointer and length to the key
a0 = 0x00020000
a1 = 4
// Pointer and length to the data.
a2 = 0x00020004
a3 = 76
// Call "write" host function.
ecalli 3
trap
// Tests the "bless" host function.
pub @bless_host_fn:
// Manager
a0 = 1
// Authorizers
a1 = 2
// Validators
a2 = 3
// Load service id 10 in memory.
u32 [0x00020000] = 10
// Give it some free amount of gas.
u32 [0x00020004] = 1000
u32 [0x00020008] = 0
// Address for extra services
a3 = 0x00020000
// Number of extra services
a4 = 1
// Call the "bless" host function.
ecalli 5
trap
// Tests the "assign" host function.
pub @assign_host_fn:
// Change the first authorizer hash.
u8 [0x00020000] = 128
// Core index.
a0 = 0
// Memory address where assignments start.
a1 = 0x00020000
// Call "assign" host function.
ecalli 6
trap
// Tests the "designate" host function.
pub @designate_host_fn:
// Simple loop for putting 128 336 times.
s0 = 0
@designate_host_fn_loop:
u8 [s0 + 0x00020000] = 128
s0 = s0 + 1
jump @designate_host_fn_loop if s0 <u 336
// Address in memory of new validators.
a0 = 0x00020000
// Call "designate" host function.
ecalli 7
trap
// Tests the "checkpoint" host function.
// It's meant to run out of gas in the middle of execution.
pub @checkpoint_host_fn:
// We first write something to storage.
// Key.
u8 [0x00020000] = 107
u8 [0x00020001] = 101
u8 [0x00020002] = 121
// Value.
u32 [0x00020003] = 1224
// Set parameters for "write" host function.
// Pointer and length to key.
a0 = 0x00020000
a1 = 3
// Pointer and length to value.
a2 = 0x00020003
a3 = 4
// Call "write" host function.
ecalli 3
// Call "checkpoint" host function.
ecalli 8
// We are adding the code for overriding the key in
// storage but it's not meant to execute because of
// lack of gas.
// Override value.
u32 [0x00020003] = 1337
// Set parameters.
a0 = 0x00020000
a1 = 3
a2 = 0x00020003
a3 = 4
// Call "write".
ecalli 3
trap
// Tests the "new" host function.
pub @new_host_fn:
// Address of code hash.
a0 = 0x00020000
// Code length.
a1 = 1
// Min gas accumulate.
a2 = 1000
a3 = 0
// Min gas on transfer.
a4 = 500
a5 = 0
// Call "new" host function.
ecalli 9
trap
// Tests the "upgrade" host function.
pub @upgrade_host_fn:
// Address of code hash.
a0 = 0x00020000
// Simple loop for putting 128 32 times.
s0 = 0
@upgrade_host_fn_loop:
u8 [s0 + 0x00020000] = 128
s0 = s0 + 1
jump @upgrade_host_fn_loop if s0 <u 32
// Min gas accumulate.
a1 = 0
a2 = 1000
// Min gas on transfer.
a3 = 0
a4 = 500
// Call "upgrade" host function.
ecalli 10
trap
// Tests the "transfer" host function.
pub @transfer_host_fn:
// Destination service.
a0 = 0
// Amount.
a1 = 1000
a2 = 0
// Gas limit.
a3 = 10
a4 = 0
// Memo.
a5 = 0x00020000
u8 [0x00020000] = 65
u8 [0x00020001] = 105
u8 [0x00020002] = 114
u8 [0x00020003] = 100
u8 [0x00020004] = 114
u8 [0x00020005] = 111
u8 [0x00020006] = 112
// Call "transfer" host function.
ecalli 11
trap
// Tests the "eject" host function.
pub @eject_host_fn:
// Destination service.
a0 = 0
// Memo.
a1 = 0x00020000
u8 [0x00020000] = 84
u8 [0x00020001] = 101
u8 [0x00020002] = 115
u8 [0x00020003] = 116
// Call "eject" host function.
ecalli 12
trap
// Tests the "query" host function.
pub @query_host_fn:
// TODO
trap
// Tests the "solicit" host function.
pub @solicit_host_fn:
// Hash.
a0 = 0x00020000
// Simple loop for putting 128 32 times.
s0 = 0
@solicit_host_fn_loop:
u8 [s0 + 0x00020000] = 128
s0 = s0 + 1
jump @solicit_host_fn_loop if s0 <u 32
// Preimage length.
a1 = 1
// Call "solicit" host function.
ecalli 14
trap
// Tests the "forget" host function.
pub @forget_host_fn:
// Hash.
a0 = 0x00020000
// Simple loop for putting 128 32 times.
s0 = 0
@forget_host_fn_loop:
u8 [s0 + 0x00020000] = 128
s0 = s0 + 1
jump @forget_host_fn_loop if s0 <u 32
// Preimage length.
a1 = 1
// Call "forget" host function.
ecalli 15
trap
// Tests the "yield" host function.
pub @yield_host_fn:
// TODO
trap
// Tests the "historical lookup" host function.
pub @historical_lookup_host_fn:
// Target service 0.
a0 = 0
// Preimage hash.
a1 = 0x00020000
u8 [0x00020000] = 128
// Preimage destination.
a2 = 0x00020100
// Call "historical lookup" host function.
ecalli 17
// Return preimage.
// From.
a3 = 0x00020100
// To.
a4 = 0x00020104
// Halt.
a0 = 4294901760
jump [a0]
trap
// Tests the "fetch" host function.
pub @fetch_host_fn:
// We want the first fetch.
a0 = 0
// Then we put it in the following address.
a1 = 0x00020000
// Some length
a2 = 10
// Call "fetch" host function.
ecalli 18
// Return preimage.
// From.
a3 = 0x00020000
// To.
a4 = 0x00020010
// Halt.
a0 = 4294901760
jump [a0]
trap
// Tests the "export" host function.
pub @export_host_fn:
// Export address.
a0 = 0x00020000
// Export length.
a1 = 6
// "export"
u8 [0x00020000] = 101
u8 [0x00020001] = 120
u8 [0x00020002] = 112
u8 [0x00020003] = 111
u8 [0x00020004] = 114
u8 [0x00020005] = 116
// Call "export" host function.
ecalli 19
// Halt.
a0 = 4294901760
jump [a0]
trap
pub @machine_host_fn:
// Code address.
a0 = 0x00020000
// Code length.
a1 = 10
// Program counter.
a2 = 0
// Call "machine" host function.
// This creates the machine and puts its id in register a0.
ecalli 20
a0 = 0x00020000
ecalli 20
a0 = 0x00020000
ecalli 20
// Let's return it.
u32 [0x00020000] = a0
// From.
a3 = 0x00020000
// To.
a4 = 0x00020003
// Halt.
a0 = 4294901760
jump [a0]
trap
// Tests the "peek" host function.
pub @peek_host_fn:
// First we create the machine.
a0 = 0x00020000
a1 = 10
a2 = 0
ecalli 20
// Then we add something to its memory.
// But first we have to initialize a memory page to write to.
// Machine id.
a0 = 0
// From page.
a1 = 32
// To page.
a2 = 33
// Call the "zero" host function.
ecalli 23
// Machine id.
a0 = 0
// Address to read from main memory.
a1 = 0x00020000
u32 [0x00020000] = 1224
// Address to write to submachine memory.
a2 = 0x00020000
// Length.
a3 = 4
// We write to memory with the "poke" host function.
ecalli 22
// Now we can peek into its memory.
// Machine id.
a0 = 0
// Address to write the peeked value.
a1 = 0x00020010
// Address to read from submachine memory.
a2 = 0x00020000
// Length.
a3 = 4
// Call "peek" host function.
ecalli 21
// Now we return the peeked value from memory.
a3 = 0x00020010
a4 = 0x00020013
// Halt.
a0 = 4294901760
jump [a0]
trap
// Tests the "poke" host function.
pub @poke_host_fn:
// Already tested alongside "peek".
trap
// Tests the "zero" host function.
pub @zero_host_fn:
// TODO
trap
// Tests the "void" host function.
pub @void_host_fn:
// TODO
trap
// Tests the "invoke" host function.
pub @invoke_host_fn:
// We first need to create a machine.
// Code.
a0 = 0x00020000
// Code length.
a1 = 41
// Load fibonacci program to memory starting at 0x00020000.
jump @load_fibonacci
@after_load_fibonacci:
// Program counter.
a2 = 0
// Create.
ecalli 20
// Now we invoke it.
// Machine id.
a0 = 0
// Address of gas and registers.
a1 = 0x00020100
// Loads gas and registers starting at 0x00020100
jump @load_gas_and_registers
@after_gas_and_registers:
// Call "invoke" host function.
ecalli 25
// Result is in w_7 of the submachine.
// We return it.
a3 = 0x00020100
a4 = 0x0002016f
// Halt.
a0 = 4294901760
jump [a0]
trap
// Loads a fibonacci program in memory.
// From 0x00020000 to 0x00020028
@load_fibonacci:
// Preface.
u8 [0x00020000] = 0
u8 [0x00020001] = 0
u8 [0x00020002] = 33
// load_imm 8 1
u8 [0x00020003] = 51
u8 [0x00020004] = 8
u8 [0x00020005] = 1
// load_imm 9 1
u8 [0x00020006] = 51
u8 [0x00020007] = 9
u8 [0x00020008] = 1
// jump 3
u8 [0x00020009] = 40
u8 [0x0002000a] = 3
// trap
u8 [0x0002000b] = 0
// add_imm_64 7 7 8
u8 [0x0002000c] = 149
u8 [0x0002000d] = 119
u8 [0x0002000e] = 255
// branch_eq_imm 7 0 12
u8 [0x0002000f] = 81
u8 [0x00020010] = 7
u8 [0x00020011] = 12
// move_reg 8 10
u8 [0x00020012] = 100
u8 [0x00020013] = 138
// add_64 9 8 8
u8 [0x00020014] = 200
u8 [0x00020015] = 152
u8 [0x00020016] = 8
// move_reg 10 9
u8 [0x00020017] = 100
u8 [0x00020018] = 169
// jump -13
u8 [0x00020019] = 40
u8 [0x0002001a] = 243
// move_reg 8 7
u8 [0x0002001b] = 100
u8 [0x0002001c] = 135
// load_imm 8 0
u8 [0x0002001d] = 51
u8 [0x0002001e] = 8
// load_imm 9 0
u8 [0x0002001f] = 51
u8 [0x00020020] = 9
// fallthrough
u8 [0x00020021] = 1
// jump_ind 0 0
u8 [0x00020022] = 50
u8 [0x00020023] = 0
// Opcode bitmask.
u8 [0x00020024] = 73
u8 [0x00020025] = 147
u8 [0x00020026] = 82
u8 [0x00020027] = 213
u8 [0x00020028] = 0
jump @after_load_fibonacci
@load_gas_and_registers:
// Gas
u32 [0x00020100] = 10000
u32 [0x00020104] = 0
// w_0
u32 [0x00020108] = 4294901760
u32 [0x0002010c] = 0
// w_1
u32 [0x00020110] = 0
u32 [0x00020114] = 0
// w_2
u32 [0x00020118] = 0
u32 [0x0002011c] = 0
// w_3
u32 [0x00020120] = 0
u32 [0x00020124] = 0
// w_4
u32 [0x00020128] = 0
u32 [0x0002012c] = 0
// w_5
u32 [0x00020130] = 0
u32 [0x00020134] = 0
// w_6
u32 [0x00020138] = 0
u32 [0x0002013c] = 0
// w_7
u32 [0x00020140] = 9
u32 [0x00020144] = 0
// w_8
u32 [0x00020148] = 0
u32 [0x0002014c] = 0
// w_9
u32 [0x00020150] = 0
u32 [0x00020154] = 0
// w_10
u32 [0x00020158] = 0
u32 [0x0002015c] = 0
// w_11
u32 [0x00020160] = 0
u32 [0x00020164] = 0
// w_12
u32 [0x00020168] = 0
u32 [0x0002016c] = 0
jump @after_gas_and_registers
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment