module Blockchain.VM.VMState (
VMState(..),
Memory(..),
startingState,
VMException(..),
addErr
-- getReturnValue
) where
import Control.Monad
import qualified Data.Vector.Unboxed.Mutable as V
import qualified Data.ByteString as B
import Data.IORef
import Data.Word
import Blockchain.ExtWord
import Blockchain.Format
import Blockchain.VM.Code
data VMException = OutOfGasException | StackTooSmallException | VMException String | MalformedOpcodeException deriving (Show)
addErr::String->Code->VMState->IO VMState
addErr message c state = do
let (op, _) = getOperationAt c (pc state)
return state{vmException=Just $ VMException (message ++ " for a call to " ++ show op)}
data Memory =
Memory {
mVector::V.IOVector Word8,
mSize::IORef Word256
}
newMemory::IO Memory
newMemory = do
arr <- V.new 100
size <- newIORef 0
forM_ [0..99] $ \p -> V.write arr p 0
return $ Memory arr size
data VMState =
VMState {
vmGasRemaining::Integer,
pc::Int,
memory::Memory,
stack::[Word256],
callDepth::Int,
refund::Integer,
markedForSuicide::Bool,
done::Bool,
returnVal::Maybe B.ByteString,
vmException::Maybe VMException
}
instance Format VMState where
format state =
"pc: " ++ show (pc state) ++ "\n" ++
"done: " ++ show (done state) ++ "\n" ++
"gasRemaining: " ++ show (vmGasRemaining state) ++ "\n" ++
"stack: " ++ show (stack state) ++ "\n"
startingState::IO VMState
startingState = do
m <- newMemory
return VMState
{
pc = 0,
done=False,
returnVal=Nothing,
vmException=Nothing,
vmGasRemaining=0,
stack=[],
memory=m,
callDepth=0,
refund=0,
markedForSuicide=False
}
{-
getReturnValue::VMState->IO B.ByteString
getReturnValue state =
case stack state of
[add, size] -> mLoadByteString (memory state) add size
[] -> return B.empty --Happens when STOP is called
--TODO- This needs better error handling other than to just crash if the stack isn't 2 items long
_ -> error "Error in getReturnValue: VM ended with stack in an unsupported case"
-}