mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-26 23:32:15 +00:00
140 lines
2.5 KiB
Go
140 lines
2.5 KiB
Go
package vm
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
var (
|
|
ErrDataStackOverflow = errors.New("DataStackOverflow")
|
|
ErrDataStackUnderflow = errors.New("DataStackUnderflow")
|
|
)
|
|
|
|
type Word [4]uint64
|
|
|
|
func Bytes2Uint64(bz []byte) uint64 {
|
|
return binary.LittleEndian.Uint64(bz)
|
|
}
|
|
|
|
func Uint642Bytes(dest []byte, i uint64) {
|
|
binary.LittleEndian.PutUint64(dest, i)
|
|
}
|
|
|
|
// Not goroutine safe
|
|
type Stack struct {
|
|
data []Word
|
|
ptr int
|
|
|
|
gas *uint64
|
|
err *error
|
|
}
|
|
|
|
func NewStack(capacity int, gas *uint64, err *error) *Stack {
|
|
return &Stack{
|
|
data: make([]Word, capacity),
|
|
ptr: 0,
|
|
gas: gas,
|
|
err: err,
|
|
}
|
|
}
|
|
|
|
func (st *Stack) Push(d Word) error {
|
|
if st.ptr == cap(st.data) {
|
|
return ErrDataStackOverflow
|
|
}
|
|
st.data[st.ptr] = d
|
|
st.ptr++
|
|
}
|
|
|
|
func (st *Stack) Push64(i uint64) error {
|
|
if st.ptr == cap(st.data) {
|
|
return ErrDataStackOverflow
|
|
}
|
|
st.data[st.ptr] = [4]uint64{i, 0, 0, 0}
|
|
st.ptr++
|
|
}
|
|
|
|
func (st *Stack) PushBytes(bz []byte) error {
|
|
if len(bz) != 32 {
|
|
panic("Invalid bytes size: expected 32")
|
|
}
|
|
if st.ptr == cap(st.data) {
|
|
return ErrDataStackOverflow
|
|
}
|
|
st.data[st.ptr] = [4]uint64{
|
|
Bytes2Uint64(bz[0:8]),
|
|
Bytes2Uint64(bz[8:16]),
|
|
Bytes2Uint64(bz[16:24]),
|
|
Bytes2Uint64(bz[24:32]),
|
|
}
|
|
st.ptr++
|
|
}
|
|
|
|
func (st *Stack) Pop() (Word, error) {
|
|
if st.ptr == 0 {
|
|
return Zero, ErrDataStackUnderflow
|
|
}
|
|
st.ptr--
|
|
return st.data[st.ptr], nil
|
|
}
|
|
|
|
func (st *Stack) Pop64() (uint64, error) {
|
|
if st.ptr == 0 {
|
|
return Zero, ErrDataStackUnderflow
|
|
}
|
|
st.ptr--
|
|
return st.data[st.ptr][0], nil
|
|
}
|
|
|
|
func (st *Stack) PopBytes() ([]byte, error) {
|
|
if st.ptr == 0 {
|
|
return Zero, ErrDataStackUnderflow
|
|
}
|
|
st.ptr--
|
|
res := make([]byte, 32)
|
|
copy(res[0:8], Uint642Bytes(st.data[st.ptr][0]))
|
|
copy(res[8:16], Uint642Bytes(st.data[st.ptr][1]))
|
|
copy(res[16:24], Uint642Bytes(st.data[st.ptr][2]))
|
|
copy(res[24:32], Uint642Bytes(st.data[st.ptr][3]))
|
|
return res, nil
|
|
}
|
|
|
|
func (st *Stack) Len() int {
|
|
return st.ptr
|
|
}
|
|
|
|
func (st *Stack) Swap(n int) error {
|
|
if st.ptr < n {
|
|
return ErrDataStackUnderflow
|
|
}
|
|
st.data[st.ptr-n], st.data[st.ptr-1] = st.data[st.ptr-1], st.data[st.ptr-n]
|
|
return nil
|
|
}
|
|
|
|
func (st *Stack) Dup(n int) {
|
|
st.Push(st.data[st.ptr-n])
|
|
}
|
|
|
|
func (st *Stack) Peek() Word {
|
|
return st.data[st.ptr-1]
|
|
}
|
|
|
|
func (st *Stack) Require(n int) error {
|
|
if st.ptr < n {
|
|
return ErrDataStackUnderflow
|
|
}
|
|
}
|
|
|
|
func (st *Stack) Print() {
|
|
fmt.Println("### stack ###")
|
|
if st.ptr > 0 {
|
|
for i, val := range st.data {
|
|
fmt.Printf("%-3d %v\n", i, val)
|
|
}
|
|
} else {
|
|
fmt.Println("-- empty --")
|
|
}
|
|
fmt.Println("#############")
|
|
}
|