From 8e5374b338e18b741e013840d4987852254d54f5 Mon Sep 17 00:00:00 2001 From: jed Date: Wed, 5 Sep 2012 16:54:14 -0700 Subject: [PATCH] contract stuff. Still aways a way I just wanted to get it in github. --- src/Contract.cpp | 35 ++++ src/Contract.h | 30 +++ src/Interpreter.cpp | 367 +++++++++++++++++++++++++++++++++++++ src/Interpreter.h | 85 +++++++++ src/ScriptData.cpp | 1 + src/ScriptData.h | 94 ++++++++++ src/TransactionEngine.cpp | 11 +- src/TransactionFormats.cpp | 2 +- 8 files changed, 619 insertions(+), 6 deletions(-) create mode 100644 src/Contract.cpp create mode 100644 src/Contract.h create mode 100644 src/Interpreter.cpp create mode 100644 src/Interpreter.h create mode 100644 src/ScriptData.cpp create mode 100644 src/ScriptData.h diff --git a/src/Contract.cpp b/src/Contract.cpp new file mode 100644 index 0000000000..09c3a4ecfc --- /dev/null +++ b/src/Contract.cpp @@ -0,0 +1,35 @@ +#include "Contract.h" +#include "Interpreter.h" + +using namespace Script; +/* +JED: V III +*/ + +Contract::Contract() +{ + +} + + +void Contract::executeCreate() +{ + +} +void Contract::executeRemove() +{ + +} +void Contract::executeFund() +{ + +} +void Contract::executeAccept() +{ + //std::vector code; + + //Interpreter interpreter; + //interpreter.interpret(this,code); +} + + diff --git a/src/Contract.h b/src/Contract.h new file mode 100644 index 0000000000..76d30dc54a --- /dev/null +++ b/src/Contract.h @@ -0,0 +1,30 @@ +#ifndef __CONTRACT__ +#define __CONTRACT__ + +#include "SerializedLedger.h" +#include +#include "ScriptData.h" +/* + Encapsulates the SLE for a Contract +*/ + +class Contract +{ +public: + Contract(); + + uint160& getIssuer(); + uint160& getOwner(); + STAmount& getRippleEscrow(); + uint32 getEscrow(); + uint32 getBond(); + + Script::Data getData(int index); + + void executeCreate(); + void executeRemove(); + void executeFund(); + void executeAccept(); +}; + +#endif \ No newline at end of file diff --git a/src/Interpreter.cpp b/src/Interpreter.cpp new file mode 100644 index 0000000000..0b370683f9 --- /dev/null +++ b/src/Interpreter.cpp @@ -0,0 +1,367 @@ +#include "Interpreter.h" +#include "Config.h" + +/* +We also need to charge for each op + +*/ + +namespace Script { + + +////////////////////////////////////////////////////////////////////////// +/// Operations + +int Operation::getFee() +{ + return(theConfig.FEE_CONTRACT_OPERATION); +} + +// this is just an Int in the code +class IntOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data=interpreter->getIntData(); + if(data->isInt32()) + { + interpreter->pushStack( data ); + return(true); + } + return(false); + } +}; + +class FloatOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data=interpreter->getFloatData(); + if(data->isFloat()) + { + interpreter->pushStack( data ); + return(true); + } + return(false); + } +}; + +class Uint160Op : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data=interpreter->getUint160Data(); + if(data->isUint160()) + { + interpreter->pushStack( data ); + return(true); + } + return(false); + } +}; + +class AddOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data1=interpreter->popStack(); + Data::pointer data2=interpreter->popStack(); + if( (data1->isInt32() || data1->isFloat()) && + (data2->isInt32() || data2->isFloat()) ) + { + if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()+data2->getFloat()))); + else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()+data2->getInt()))); + return(true); + }else + { + return(false); + } + } +}; + +class SubOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data1=interpreter->popStack(); + Data::pointer data2=interpreter->popStack(); + if( (data1->isInt32() || data1->isFloat()) && + (data2->isInt32() || data2->isFloat()) ) + { + if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()-data2->getFloat()))); + else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()-data2->getInt()))); + return(true); + }else + { + return(false); + } + } +}; + + +class StartBlockOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer offset=interpreter->getIntData(); + return(interpreter->startBlock(offset->getInt())); + } +}; + +class EndBlockOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + return(interpreter->endBlock()); + } +}; + +class StopOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + interpreter->stop(); + return(true); + } +}; + +class AcceptDataOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data=interpreter->popStack(); + if(data->isInt32()) + { + interpreter->pushStack( interpreter->getAcceptData(data->getInt()) ); + return(true); + } + return(false); + } +}; + +class JumpIfOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer offset=interpreter->getIntData(); + Data::pointer cond=interpreter->popStack(); + if(cond->isBool() && offset->isInt32()) + { + if(cond->isTrue()) + { + return(interpreter->jumpTo(offset->getInt())); + } + return(true); + } + return(false); + } +}; + +class JumpOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer offset=interpreter->getIntData(); + if(offset->isInt32()) + { + return(interpreter->jumpTo(offset->getInt())); + } + return(false); + } +}; + +class SendXNSOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer sourceID=interpreter->popStack(); + Data::pointer destID=interpreter->popStack(); + Data::pointer amount=interpreter->popStack(); + if(sourceID->isUint160() && destID->isUint160() && amount->isInt32() && interpreter->canSign(sourceID->getUint160())) + { + // make sure: + // source is either, this contract, issuer, or acceptor + + // TODO do the send + //interpreter->pushStack( send result); + + return(true); + } + + return(false); + } +}; + +class GetDataOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer index=interpreter->popStack(); + if(index->isInt32()) + { + interpreter->pushStack( interpreter->getContractData(index->getInt())); + return(true); + } + + return(false); + } +}; + +////////////////////////////////////////////////////////////////////////// + +Interpreter::Interpreter() +{ + mContract=NULL; + mCode=NULL; + mInstructionPointer=0; + mTotalFee=0; + + mInBlock=false; + mBlockSuccess=true; + mBlockJump=0; + + mFunctionTable.resize(NUM_OF_OPS); + + mFunctionTable[INT_OP]=new IntOp(); + mFunctionTable[FLOAT_OP]=new FloatOp(); + mFunctionTable[UINT160_OP]=new Uint160Op(); + + mFunctionTable[ADD_OP]=new AddOp(); + mFunctionTable[SUB_OP]=new SubOp(); + +} + +Data::pointer Interpreter::popStack() +{ + if(mStack.size()) + { + Data::pointer item=mStack[mStack.size()-1]; + mStack.pop_back(); + return(item); + }else + { + return(Data::pointer(new ErrorData())); + } +} + +void Interpreter::pushStack(Data::pointer data) +{ + mStack.push_back(data); +} + + +// offset is where to jump to if the block fails +bool Interpreter::startBlock(int offset) +{ + if(mInBlock) return(false); // can't nest blocks + mBlockSuccess=true; + mInBlock=true; + mBlockJump=offset+mInstructionPointer; + return(true); +} + +bool Interpreter::endBlock() +{ + if(!mInBlock) return(false); + mInBlock=false; + mBlockJump=0; + pushStack(Data::pointer(new BoolData(mBlockSuccess))); + return(true); +} + +TER Interpreter::interpret(Contract* contract,const SerializedTransaction& txn,std::vector& code) +{ + mContract=contract; + mCode=&code; + mTotalFee=0; + mInstructionPointer=0; + while(mInstructionPointer=mFunctionTable.size()) + { + // TODO: log + return(temMALFORMED); // TODO: is this actually what we want to do? + } + + mTotalFee += mFunctionTable[ fun ]->getFee(); + if(mTotalFee>txn.getTransactionFee().getNValue()) + { + // TODO: log + return(telINSUF_FEE_P); + }else + { + if(!mFunctionTable[ fun ]->work(this)) + { + // TODO: log + return(temMALFORMED); // TODO: is this actually what we want to do? + } + } + } + return(tesSUCCESS); +} + + +Data::pointer Interpreter::getIntData() +{ + int value=0; // TODO + mInstructionPointer += 4; + return(Data::pointer(new IntData(value))); +} + +Data::pointer Interpreter::getFloatData() +{ + float value=0; // TODO + mInstructionPointer += 4; + return(Data::pointer(new FloatData(value))); +} + +Data::pointer Interpreter::getUint160Data() +{ + uint160 value; // TODO + mInstructionPointer += 20; + return(Data::pointer(new Uint160Data(value))); +} + + + +bool Interpreter::jumpTo(int offset) +{ + mInstructionPointer += offset; + if( (mInstructionPointer<0) || (mInstructionPointer>mCode->size()) ) + { + mInstructionPointer -= offset; + return(false); + } + return(true); +} + +void Interpreter::stop() +{ + mInstructionPointer=mCode->size(); +} + +Data::pointer Interpreter::getContractData(int index) +{ + return(Data::pointer(new ErrorData())); +} + + + + +} // end namespace diff --git a/src/Interpreter.h b/src/Interpreter.h new file mode 100644 index 0000000000..5d8f58b009 --- /dev/null +++ b/src/Interpreter.h @@ -0,0 +1,85 @@ +#ifndef __INTERPRETER__ +#define __INTERPRETER__ + +#include "uint256.h" +#include "Contract.h" +#include +#include +#include "ScriptData.h" +#include "TransactionEngine.h" + +namespace Script { + +class Interpreter; + +// Contracts are non typed have variable data types + + +class Operation +{ +public: + // returns false if there was an error + virtual bool work(Interpreter* interpreter)=0; + + virtual int getFee(); +}; + +class Interpreter +{ + std::vector mFunctionTable; + + std::vector mStack; + + Contract* mContract; + std::vector* mCode; + unsigned int mInstructionPointer; + int mTotalFee; + + bool mInBlock; + int mBlockJump; + bool mBlockSuccess; + +public: + enum { INT_OP,FLOAT_OP,UINT160_OP,BOOL_OP,PATH_OP, + ADD_OP,SUB_OP,MUL_OP,DIV_OP,MOD_OP, + GTR_OP,LESS_OP,EQUAL_OP,NOT_EQUAL_OP, + AND_OP,OR_OP,NOT_OP, + BLOCK_OP, BLOCK_END_OP, + JUMP_OP, JUMPIF_OP, + STOP_OP, + SET_DATA_OP,GET_DATA_OP, GET_ISSUER_ID_OP, GET_OWNER_ID_OP, GET_LEDGER_TIME_OP, + ACCEPT_DATA_OP, + SEND_XNS_OP, NUM_OF_OPS }; + + Interpreter(); + + // returns a TransactionEngineResult + TER interpret(Contract* contract,const SerializedTransaction& txn,std::vector& code); + + void stop(); + + bool canSign(uint160& signer); + + int getInstructionPointer(){ return(mInstructionPointer); } + void setInstructionPointer(int n){ mInstructionPointer=n;} + + Data::pointer popStack(); + void pushStack(Data::pointer data); + bool jumpTo(int offset); + + bool startBlock(int offset); + bool endBlock(); + + + Data::pointer getIntData(); + Data::pointer getFloatData(); + Data::pointer getUint160Data(); + Data::pointer getAcceptData(int index); + Data::pointer getContractData(int index); + + +}; + +} // end namespace + +#endif \ No newline at end of file diff --git a/src/ScriptData.cpp b/src/ScriptData.cpp new file mode 100644 index 0000000000..52442c0d17 --- /dev/null +++ b/src/ScriptData.cpp @@ -0,0 +1 @@ +#include "ScriptData.h" \ No newline at end of file diff --git a/src/ScriptData.h b/src/ScriptData.h new file mode 100644 index 0000000000..af9ce45c0e --- /dev/null +++ b/src/ScriptData.h @@ -0,0 +1,94 @@ +#ifndef __SCRIPT_DATA__ +#define __SCRIPT_DATA__ +#include "uint256.h" +#include + +namespace Script { +class Data +{ +public: + typedef boost::shared_ptr pointer; + + virtual bool isInt32(){ return(false); } + virtual bool isFloat(){ return(false); } + virtual bool isUint160(){ return(false); } + virtual bool isError(){ return(false); } + virtual bool isTrue(){ return(false); } + virtual bool isBool(){ return(false); } + //virtual bool isBlockEnd(){ return(false); } + + virtual int getInt(){ return(0); } + virtual float getFloat(){ return(0); } + virtual uint160 getUint160(){ return(0); } + + //virtual bool isCurrency(){ return(false); } +}; + +class IntData : public Data +{ + int mValue; +public: + IntData(int value) + { + mValue=value; + } + bool isInt32(){ return(true); } + int getInt(){ return(mValue); } + float getFloat(){ return((float)mValue); } + bool isTrue(){ return(mValue!=0); } +}; + +class FloatData : public Data +{ + float mValue; +public: + FloatData(float value) + { + mValue=value; + } + bool isFloat(){ return(true); } + float getFloat(){ return(mValue); } + bool isTrue(){ return(mValue!=0); } +}; + +class Uint160Data : public Data +{ + uint160 mValue; +public: + Uint160Data(uint160 value) + { + mValue=value; + } + bool isUint160(){ return(true); } + uint160 getUint160(){ return(mValue); } +}; + +class BoolData : public Data +{ + bool mValue; +public: + BoolData(bool value) + { + mValue=value; + } + bool isBool(){ return(true); } + bool isTrue(){ return(mValue); } +}; + +class ErrorData : public Data +{ +public: + bool isError(){ return(true); } +}; + +class BlockEndData : public Data +{ +public: + bool isBlockEnd(){ return(true); } +}; + + +} + + +#endif \ No newline at end of file diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index aef58f3b4d..af72e38d78 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -17,6 +17,8 @@ #include "Log.h" #include "TransactionFormats.h" #include "utils.h" +#include "Interpreter.h" +#include "Contract.h" // Small for testing, should likely be 32 or 64. #define DIR_NODE_MAX 2 @@ -4659,8 +4661,6 @@ void TransactionEngine::calcNodeOffer( } #endif -#include "Interpreter.h" -#include "Contract.h" TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) { @@ -4693,8 +4693,8 @@ TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) //if( txn.getSourceAccount() ) Contract contract; - Interpreter interpreter; - TER terResult=interpreter->interpret(&contract,txn,createCode); + Script::Interpreter interpreter; + TER terResult=interpreter.interpret(&contract,txn,createCode); if(tesSUCCESS != terResult) { @@ -4705,7 +4705,8 @@ TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) TER TransactionEngine::doContractRemove(const SerializedTransaction& txn) { - + // TODO: + return(tesSUCCESS); } // vim:ts=4 diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 5260b6bb66..de18524c7c 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -127,7 +127,7 @@ TransactionFormat InnerTxnFormats[]= }, { "Contract", ttCONTRACT_REMOVE, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(ContractID), STI_ACCOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(Target), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } },