sealevel: run SPL token program
This commit is contained in:
parent
ce9887728d
commit
a940a46699
|
@ -1,3 +1,4 @@
|
|||
// Package fixtures contains test data
|
||||
package fixtures
|
||||
|
||||
import (
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7b44674b9704fa7640fbebfac68389f338b500b8c2bc29175c27ed66838b5a3c
|
||||
size 134080
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -27,6 +27,7 @@ type VMOpts struct {
|
|||
// Machine parameters
|
||||
HeapSize int
|
||||
Syscalls SyscallRegistry
|
||||
Tracer TraceSink
|
||||
|
||||
// Execution parameters
|
||||
Context any // passed to syscalls
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue