From d4ee0b562da30c5a0f82fa091caecac278aa58c5 Mon Sep 17 00:00:00 2001 From: leovct Date: Wed, 17 Jul 2024 12:33:04 +0200 Subject: [PATCH] docs: update interfaces --- README.md | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ memory.go | 13 +++++----- stack.go | 9 ++++--- storage.go | 9 ++++--- 4 files changed, 92 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index db27ebe..e53b185 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,74 @@ The aim is to keep it simple, quick to implement and interesting to learn more a Inspired by [gevm](https://github.com/Jesserc/gevm) by [Jesserc](https://twitter.com/jesserc_). +## EVM + +```go +type IEVM interface { + //// Stack operations + // Push an item to the stack. + Push(*uint256.Int) error + + // Pop an item from the stack. + Pop() (*uint256.Int, error) + + //// Math operations + // Add the top two elements of the stack and push the result, x + y, back to the stack. + Add() error + + // Multiply the top two elements of the stack and push the result, x * y, back to the stack. + Mul() error + + // Subtract the top two elements of the stack and push the result, x - y, back to the stack. + Sub() error + + // Perform the integer divison operation on the top two elements of the stack and push the result, x // y, back to the stack. + Div() error + + // Perform the signed integer division operation (trunced) on the top two elements of the stack and push the result, x // y, back to the stack. + SDiv() error + + // Perform the modulo remained operation on the top two elements of the stack and push the result, x % y, back to the stack. + Mod() error + + // Perform the signed modulo remained operation on the top two elements of the stack and push the result, x % y, back to the stack. + SMod() error + + // Perform the modulo addition operation on the top two elements of the stack and push the result, (x + y) % m, back to the stack. + // The third top element of the stack is the integer denominator m. + AddMod() error + + // Perform the modulo multiplication operation on the top two elements of the stack and push the result, (x * y) % m, back to the stack. + // The third top element of the stack is the integer denominator N. + MulMod() error + + // Perform the exponential operation on the top two elements of the stack and push the result, x ** y, back to the stack. + Exp() error + + // Extend the length of two’s complement signed integer. + // The first top element of the stack, b, represents the size in byte - 1 of the integer to sign extend. + // The second top element of the stack, x, represents the integer value to sign extend. + SignExtend() error +} + +// EVM represents an Ethereum Virtual Machine. +type EVM struct { + stack IStack + memory IMemory + storage IStorage +} +``` + ## Stack ```go type IStack interface { + // Push adds a new element to the top of the stack. + // It returns an error if the stack is full. Push(*uint256.Int) error + + // Pop removes and returns the top element from the stack. + // If the stack is empty, it returns a zero-value 32-byte array and an error. Pop() (*uint256.Int, error) } @@ -24,7 +87,14 @@ type Stack struct { ```go type IMemory interface { + // Store writes a byte slice to memory at the specified offset. + // If the offset plus the length of the value exceeds the current memory size, + // the memory is automatically expanded to accommodate the new data. Store(value []byte, offset int) + + // Access retrieves a slice of memory starting at the given offset with the specified size. + // It handles cases where the requested region may extend beyond the current memory size. + // Returns a byte slice of length 'size', zero-padded if necessary. Access(offset, size int) []byte } @@ -38,7 +108,12 @@ type Memory struct { ```go type IStorage interface { + // Store writes a 32-byte word to storage at the specified key. + // If the key already exists, its value will be overwritten. Store(key int, value [32]byte) + + // Load retrieves a 32-byte word from storage using the specified key. + // If the key does not exist in the storage, it returns an empty 32-byte word. Load(key int) [32]byte } diff --git a/memory.go b/memory.go index b4b9c08..b7fef2d 100644 --- a/memory.go +++ b/memory.go @@ -2,7 +2,14 @@ package main // IMemory defines the methods that a memory implementation should have. type IMemory interface { + // Store writes a byte slice to memory at the specified offset. + // If the offset plus the length of the value exceeds the current memory size, + // the memory is automatically expanded to accommodate the new data. Store(value []byte, offset int) + + // Access retrieves a slice of memory starting at the given offset with the specified size. + // It handles cases where the requested region may extend beyond the current memory size. + // Returns a byte slice of length 'size', zero-padded if necessary. Access(offset, size int) []byte } @@ -16,9 +23,6 @@ func NewMemory() IMemory { return &Memory{data: make([]byte, 0)} } -// Store writes a byte slice to memory at the specified offset. -// If the offset plus the length of the value exceeds the current memory size, -// the memory is automatically expanded to accommodate the new data. func (m *Memory) Store(value []byte, offset int) { // Expand the memory if needed. requiredSize := offset + len(value) @@ -30,9 +34,6 @@ func (m *Memory) Store(value []byte, offset int) { copy(m.data[offset:], value) } -// Access retrieves a slice of memory starting at the given offset with the specified size. -// It handles cases where the requested region may extend beyond the current memory size. -// Returns a byte slice of length 'size', zero-padded if necessary. func (m *Memory) Access(offset, size int) []byte { // Return a zero-filled slice if memory is empty or offset is out of bounds. if len(m.data) == 0 || offset >= len(m.data) { diff --git a/stack.go b/stack.go index 1318a02..4b01289 100644 --- a/stack.go +++ b/stack.go @@ -18,7 +18,12 @@ var ( // IStack defines the methods that a stack implementation should have. type IStack interface { + // Push adds a new element to the top of the stack. + // It returns an error if the stack is full. Push(*uint256.Int) error + + // Pop removes and returns the top element from the stack. + // If the stack is empty, it returns a zero-value 32-byte array and an error. Pop() (*uint256.Int, error) } @@ -32,8 +37,6 @@ func NewStack() IStack { return &Stack{data: make([]uint256.Int, 0)} } -// Push adds a new element to the top of the stack. -// It returns an error if the stack is full. func (s *Stack) Push(value *uint256.Int) error { if len(s.data) >= MAX_STACK_SIZE { return ErrStackOverflow @@ -42,8 +45,6 @@ func (s *Stack) Push(value *uint256.Int) error { return nil } -// Pop removes and returns the top element from the stack. -// If the stack is empty, it returns a zero-value 32-byte array and an error. func (s *Stack) Pop() (*uint256.Int, error) { if len(s.data) == 0 { return nil, ErrStackUnderflow diff --git a/storage.go b/storage.go index 4e4cc02..314dcd7 100644 --- a/storage.go +++ b/storage.go @@ -2,7 +2,12 @@ package main // IStorage defines the methods that a storage implementation should have. type IStorage interface { + // Store writes a 32-byte word to storage at the specified key. + // If the key already exists, its value will be overwritten. Store(key int, value [32]byte) + + // Load retrieves a 32-byte word from storage using the specified key. + // If the key does not exist in the storage, it returns an empty 32-byte word. Load(key int) [32]byte } @@ -16,14 +21,10 @@ func NewStorage() IStorage { return &Storage{data: make(map[int][32]byte)} } -// Store writes a 32-byte word to storage at the specified key. -// If the key already exists, its value will be overwritten. func (s *Storage) Store(key int, value [32]byte) { s.data[key] = value } -// Load retrieves a 32-byte word from storage using the specified key. -// If the key does not exist in the storage, it returns an empty 32-byte word. func (s *Storage) Load(key int) [32]byte { return s.data[key] }