contract stuff. Still aways a way I just wanted to get it in github.

This commit is contained in:
jed
2012-09-05 16:54:14 -07:00
parent a61b5e98fe
commit 8e5374b338
8 changed files with 619 additions and 6 deletions

35
src/Contract.cpp Normal file
View File

@@ -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<char> code;
//Interpreter interpreter;
//interpreter.interpret(this,code);
}

30
src/Contract.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef __CONTRACT__
#define __CONTRACT__
#include "SerializedLedger.h"
#include <boost/shared_ptr.hpp>
#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

367
src/Interpreter.cpp Normal file
View File

@@ -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<unsigned char>& code)
{
mContract=contract;
mCode=&code;
mTotalFee=0;
mInstructionPointer=0;
while(mInstructionPointer<code.size())
{
unsigned int fun=(*mCode)[mInstructionPointer];
mInstructionPointer++;
if(fun>=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

85
src/Interpreter.h Normal file
View File

@@ -0,0 +1,85 @@
#ifndef __INTERPRETER__
#define __INTERPRETER__
#include "uint256.h"
#include "Contract.h"
#include <boost/shared_ptr.hpp>
#include <vector>
#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<Operation*> mFunctionTable;
std::vector<Data::pointer> mStack;
Contract* mContract;
std::vector<unsigned char>* 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<unsigned char>& 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

1
src/ScriptData.cpp Normal file
View File

@@ -0,0 +1 @@
#include "ScriptData.h"

94
src/ScriptData.h Normal file
View File

@@ -0,0 +1,94 @@
#ifndef __SCRIPT_DATA__
#define __SCRIPT_DATA__
#include "uint256.h"
#include <boost/shared_ptr.hpp>
namespace Script {
class Data
{
public:
typedef boost::shared_ptr<Data> 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

View File

@@ -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

View File

@@ -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 } }
},