module Decompile1
(
decompile
) where
import Control.Monad.Trans.Resource
import Data.Default
import qualified Database.LevelDB as DB
import Data.List
import System.FilePath
import Text.PrettyPrint.ANSI.Leijen hiding ((<$>), (</>))
import Blockchain.Data.RLP
import Blockchain.Data.Block
import Blockchain.Data.SignedTransaction
import Blockchain.Data.Transaction
import Blockchain.Data.TransactionReceipt
import Blockchain.Util
import Blockchain.VM.Code
import Blockchain.VM.Opcodes
--
import DumpLevelDB
import Blockchain.Format
--import Debug.Trace
formatBlock::Block->String
formatBlock = format
data StackElement = StackNumber Int | ItemDescription String deriving (Show)
stackElementSum::StackElement->StackElement->String
stackElementSum (StackNumber x) (StackNumber y) = show $ x+y
formatSE::StackElement->String
formatSE (StackNumber x) = show x
formatSE (ItemDescription s) = s
decompile::Code->String
decompile = decompile' [] 0
decompile'::[StackElement]->Int->Code->String
decompile' stack p c =
case (op, stack) of
(STOP, _) -> "STOP"
(RETURN, [memP, memSize]) -> "RETURN Mem[" ++ formatSE memP ++ ":" ++ show (memP `stackElementSum` memSize) ++ "]"
(CALLER, _) -> decompile' (ItemDescription "$CALLER":stack) (p+size) c
(GAS, _) -> decompile' (ItemDescription "$GAS":stack) (p+size) c
(POP, _:rest) -> decompile' rest (p+size) c
(SWAP1, first:second:rest) -> decompile' (second:first:rest) (p+size) c
(DUP1, first:rest) -> decompile' (first:first:rest) (p+size) c
(DUP2, first:second:rest) -> decompile' (second:first:second:rest) (p+size) c
(DUP3, v1:i1:v2:rest) -> decompile' (v2:i1:v1:rest) (p+size) c
(DUP4, v1:i1:i2:v2:rest) -> decompile' (v2:i1:i2:v1:rest) (p+size) c
(DUP5, v1:i1:i2:i3:v2:rest) -> decompile' (v2:i1:i2:i3:v1:rest) (p+size) c
(DUP6, v1:i1:i2:i3:i4:v2:rest) -> decompile' (v2:i1:i2:i3:i4:v1:rest) (p+size) c
(EXP, v1:v2:rest) -> decompile' (ItemDescription (formatSE v1 ++ "^" ++ formatSE v2):rest) (p+size) c
(SUB, v1:v2:rest) -> decompile' (ItemDescription (formatSE v1 ++ "-" ++ formatSE v2):rest) (p+size) c
(AND, v1:v2:rest) -> decompile' (ItemDescription (formatSE v1 ++ " AND " ++ formatSE v2):rest) (p+size) c
(PUSH val, _) -> decompile' (StackNumber (fromInteger $ bytes2Integer val):stack) (p+size) c
(SSTORE, (key:val:rest)) -> "STORE[" ++ formatSE key ++ "] = " ++ formatSE val ++ "\n" ++ decompile' rest (p+size) c
(MLOAD, (memP:rest)) -> decompile' (ItemDescription ("Mem[" ++ formatSE memP ++ "]"):rest) (p+size) c
(CALLDATALOAD, (dataP:rest)) -> decompile' (ItemDescription ("Data[" ++ formatSE dataP ++ "]"):rest) (p+size) c
(MSTORE, (memP:val:rest)) -> "Mem[" ++ formatSE memP ++ "] = " ++ formatSE val ++ "\n" ++ decompile' rest (p+size) c
(CODECOPY, memP:codeP:codeSize:rest) -> "CODECOPY from CODE[" ++ formatSE codeP ++ ":" ++ show (codeP `stackElementSum` codeSize) ++ "] to Mem[" ++ formatSE memP ++ ":" ++ show (memP `stackElementSum` codeSize) ++ "]\n" ++ decompile' rest (p+size) c
(CALL, gas:to:value:inOffset:inSize:outOffset:outSize:rest) -> "CALL[" ++ formatSE to ++ "] (gas=" ++ formatSE gas ++ ", value=" ++ formatSE value ++ ", inOffset = " ++ formatSE inOffset ++ ", inSize=" ++ formatSE inSize ++ ", outOffset=" ++ formatSE outOffset ++ ", outSize=" ++ formatSE outSize ++ ")\n" ++ decompile' (ItemDescription "<call result>":rest) (p+size) c
(CALL, stack) -> "CALL messup: " ++ show stack
(CALLCODE, gas:to:value:inOffset:inSize:outOffset:outSize:rest) -> "CALLCODE[" ++ formatSE to ++ "] (gas=" ++ formatSE gas ++ ", value=" ++ formatSE value ++ ", inOffset = " ++ formatSE inOffset ++ ", inSize=" ++ formatSE inSize ++ ", outOffset=" ++ formatSE outOffset ++ ", outSize=" ++ formatSE outSize ++ ")\n" ++ decompile' rest (p+size) c
(CALLCODE, stack) -> "CALLCODE messup: " ++ show stack
(JUMP, StackNumber location:rest) -> "JUMP to " ++ show location ++ "\n" ++ decompile' rest location c
(JUMP, ItemDescription location:rest) -> "JUMP to " ++ show location ++ "\n" ++ decompile' rest (p+size) c
(JUMP, _) -> "JUMP messup: " ++ show stack
_ -> show op ++ "\n" ++ decompile' stack (p+size) c
where
(op, size) = getOperationAt c p
showInit::Transaction->String
showInit ContractCreationTX {tInit=tInit'} = show (pretty tInit') ++ "\n----\n" ++ decompile tInit'
showInit MessageTX {} = ""