package evmole
import (
"bytes"
"compress/gzip"
"context"
_ "embed"
"encoding/json"
"io"
"sync"
"github.com/cdump/evmole/go/internal"
)
var wasmBinaryGz []byte
var (
wasmBinary []byte
wasmBinaryOnce sync.Once
wasmBinaryErr error
)
func getWasmBinary() ([]byte, error) {
wasmBinaryOnce.Do(func() {
r, err := gzip.NewReader(bytes.NewReader(wasmBinaryGz))
if err != nil {
wasmBinaryErr = err
return
}
defer r.Close()
wasmBinary, wasmBinaryErr = io.ReadAll(r)
})
return wasmBinary, wasmBinaryErr
}
type Options struct {
Selectors bool
Arguments bool
StateMutability bool
Storage bool
Disassemble bool
BasicBlocks bool
ControlFlowGraph bool
}
const (
optSelectors uint32 = 1
optArguments uint32 = 2
optStateMutability uint32 = 4
optStorage uint32 = 8
optDisassemble uint32 = 16
optBasicBlocks uint32 = 32
optControlFlowGraph uint32 = 64
)
func (o Options) toBitmask() uint32 {
var mask uint32
if o.Selectors {
mask |= optSelectors
}
if o.Arguments {
mask |= optArguments
}
if o.StateMutability {
mask |= optStateMutability
}
if o.Storage {
mask |= optStorage
}
if o.Disassemble {
mask |= optDisassemble
}
if o.BasicBlocks {
mask |= optBasicBlocks
}
if o.ControlFlowGraph {
mask |= optControlFlowGraph
}
return mask
}
type Analyzer struct {
runtime *internal.Runtime
}
func NewAnalyzer(ctx context.Context) (*Analyzer, error) {
wasm, err := getWasmBinary()
if err != nil {
return nil, err
}
rt, err := internal.NewRuntime(ctx, wasm)
if err != nil {
return nil, err
}
return &Analyzer{runtime: rt}, nil
}
func (a *Analyzer) Close(ctx context.Context) error {
return a.runtime.Close(ctx)
}
func (a *Analyzer) ContractInfo(ctx context.Context, code []byte, opts Options) (*Contract, error) {
jsonResult, err := a.runtime.ContractInfo(ctx, code, opts.toBitmask())
if err != nil {
return nil, err
}
var result Contract
if err := json.Unmarshal(jsonResult, &result); err != nil {
return nil, err
}
return &result, nil
}
func ContractInfo(ctx context.Context, code []byte, opts Options) (*Contract, error) {
a, err := NewAnalyzer(ctx)
if err != nil {
return nil, err
}
defer a.Close(ctx)
return a.ContractInfo(ctx, code, opts)
}