sealevel: run SPL token program

This commit is contained in:
Richard Patel 2022-09-05 09:39:40 +02:00
parent ce9887728d
commit a940a46699
7 changed files with 110 additions and 10 deletions

View File

@ -1,3 +1,4 @@
// Package fixtures contains test data
package fixtures
import (

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7b44674b9704fa7640fbebfac68389f338b500b8c2bc29175c27ed66838b5a3c
size 134080

View File

@ -22,6 +22,11 @@ type Interpreter struct {
syscalls map[uint32]Syscall
funcs map[uint32]int64
vmContext any
trace TraceSink
}
type TraceSink interface {
Printf(format string, v ...any)
}
// NewInterpreter creates a new interpreter instance for a program execution.
@ -41,6 +46,7 @@ func NewInterpreter(p *Program, opts *VMOpts) *Interpreter {
syscalls: opts.Syscalls,
funcs: p.Funcs,
vmContext: opts.Context,
trace: opts.Tracer,
}
}
@ -66,9 +72,10 @@ mainLoop:
for i := 0; true; i++ {
// Fetch
ins := ip.getSlot(pc)
fmt.Printf("% 5d [%016x, %016x, %016x, %016x, %016x, %016x, %016x, %016x, %016x, %016x, %016x] %-5d: %s\n",
i, r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], pc, GetOpcodeName(ins.Op()))
fmt.Printf(" ins=%016x op=%s\n", bits.ReverseBytes64(uint64(ins)), GetOpcodeName(ins.Op()))
if ip.trace != nil {
ip.trace.Printf("% 5d [%016x, %016x, %016x, %016x, %016x, %016x, %016x, %016x, %016x, %016x, %016x] % 5d: %s",
i, r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], pc+29 /*todo weird offset*/, disassemble(ins /*todo*/, 0))
}
// Execute
switch ins.Op() {
case OpLdxb:

View File

@ -11,7 +11,7 @@ import (
)
func TestLoader_Noop(t *testing.T) {
soNoop := fixtures.SBF(t, "noop.so")
soNoop := fixtures.Load(t, "sbf", "noop.so")
loader, err := NewLoaderFromBytes(soNoop)
require.NoError(t, err)
@ -201,7 +201,7 @@ func isZeroBytes(b []byte) bool {
}
func TestVerifier(t *testing.T) {
loader, err := NewLoaderFromBytes(fixtures.SBF(t, "noop.so"))
loader, err := NewLoaderFromBytes(fixtures.Load(t, "sbf", "noop.so"))
require.NoError(t, err)
program, err := loader.Load()

View File

@ -27,6 +27,7 @@ type VMOpts struct {
// Machine parameters
HeapSize int
Syscalls SyscallRegistry
Tracer TraceSink
// Execution parameters
Context any // passed to syscalls

View File

@ -45,14 +45,14 @@ func (p *Params) Serialize(buf *bytes.Buffer) {
if acc.IsDuplicate {
_, _ = buf.Write([]byte{acc.DuplicateIndex})
buf.Grow(7)
_ = writeZeros(buf, 7)
continue
}
_ = binary.Write(buf, binary.LittleEndian, uint8(0xFF))
_ = binary.Write(buf, binary.LittleEndian, acc.IsSigner)
_ = binary.Write(buf, binary.LittleEndian, acc.IsWritable)
_ = binary.Write(buf, binary.LittleEndian, acc.IsExecutable)
buf.Grow(4)
_ = writeZeros(buf, 4)
_, _ = buf.Write(acc.Key[:])
_, _ = buf.Write(acc.Owner[:])
_ = binary.Write(buf, binary.LittleEndian, acc.Lamports)
@ -61,8 +61,11 @@ func (p *Params) Serialize(buf *bytes.Buffer) {
// This account copy cannot be avoided without a significant redesign of the VM
_, _ = buf.Write(acc.Data[:])
acc.Padding = ReallocSpace + 1 + ((buf.Len() - 1) / ReallocAlign)
buf.Grow(acc.Padding)
acc.Padding = ReallocSpace
if offset := buf.Len() % ReallocAlign; offset != 0 {
acc.Padding += ReallocAlign - offset
}
_ = writeZeros(buf, acc.Padding)
_ = binary.Write(buf, binary.LittleEndian, acc.RentEpoch)
}
@ -126,3 +129,17 @@ func (p *Params) Update(buf *bytes.Reader) error {
_, err := buf.Read(p.ProgramID[:])
return err
}
func writeZeros(b *bytes.Buffer, n int) error {
_, err := io.Copy(b, io.LimitReader(zeroRd{}, int64(n)))
return err
}
type zeroRd struct{}
func (zeroRd) Read(buf []byte) (int, error) {
for i := range buf {
buf[i] = 0
}
return len(buf), nil
}

View File

@ -2,6 +2,7 @@ package sealevel
import (
_ "embed"
"log"
"testing"
"github.com/certusone/radiance/fixtures"
@ -35,7 +36,6 @@ func TestExecute_Memo(t *testing.T) {
err = interpreter.Run()
assert.NoError(t, err)
// TODO expose proper API for this
logs := opts.Context.(*Execution).Log.(*LogRecorder).Logs
assert.Equal(t, logs, []string{
`Memo (len 3): "Bla"`,
@ -77,3 +77,74 @@ func TestInterpreter_Noop(t *testing.T) {
"0x1, 0x2, 0x3, 0x4, 0x5\n",
})
}
func TestExecute_Token(t *testing.T) {
loader, err := loader.NewLoaderFromBytes(fixtures.Load(t, "sealevel", "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA.so"))
require.NoError(t, err)
require.NotNil(t, loader)
program, err := loader.Load()
require.NoError(t, err)
require.NotNil(t, program)
require.NoError(t, program.Verify())
tx := TxContext{}
opts := tx.newVMOpts(&Params{
Accounts: []AccountParam{
// Mint
{
IsDuplicate: false,
DuplicateIndex: 0xFF,
IsSigner: true,
IsWritable: true,
IsExecutable: false,
Key: [32]byte{0x1},
Owner: [32]byte{6, 221, 246, 225, 215, 101, 161, 147, 217, 203, 225, 70, 206, 235, 121, 172, 28, 180, 133, 237, 95, 91, 55, 145, 58, 140, 245, 133, 126, 255, 0, 169},
Lamports: 10000000,
Data: make([]byte, 82),
RentEpoch: 0,
},
// Rent sysvar
{
IsDuplicate: false,
DuplicateIndex: 0xFF,
IsSigner: true,
IsWritable: true,
IsExecutable: false,
Key: [32]byte{0x06, 0xa7, 0xd5, 0x17, 0x19, 0x2c, 0x5c, 0x51, 0x21, 0x8c, 0xc9, 0x4c, 0x3d, 0x4a, 0xf1, 0x7f, 0x58, 0xda, 0xee, 0x08, 0x9b, 0xa1, 0xfd, 0x44, 0xe3, 0xdb, 0xd9, 0x8a, 0x00, 0x00, 0x00, 0x00},
Owner: [32]byte{0x06, 0xa7, 0xd5, 0x17, 0x18, 0x75, 0xf7, 0x29, 0xc7, 0x3d, 0x93, 0x40, 0x8f, 0x21, 0x61, 0x20, 0x06, 0x7e, 0xd8, 0x8c, 0x76, 0xe0, 0x8c, 0x28, 0x7f, 0xc1, 0x94, 0x60, 0x00, 0x00, 0x00, 0x00},
Lamports: 10092,
Data: []byte{
0x98, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
0x64,
},
RentEpoch: 0,
},
},
Data: []byte{
0, 0, 0, 0,
1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
},
ProgramID: [32]byte{},
})
logger := log.Default()
logger.SetFlags(0)
opts.Tracer = logger
interpreter := sbf.NewInterpreter(program, opts)
require.NotNil(t, interpreter)
err = interpreter.Run()
assert.NoError(t, err)
logs := opts.Context.(*Execution).Log.(*LogRecorder).Logs
assert.Equal(t, logs, []string{
"Instruction: InitializeMint",
})
}