mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
contract stuff. Still aways a way I just wanted to get it in github.
This commit is contained in:
35
src/Contract.cpp
Normal file
35
src/Contract.cpp
Normal 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
30
src/Contract.h
Normal 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
367
src/Interpreter.cpp
Normal 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
85
src/Interpreter.h
Normal 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
1
src/ScriptData.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "ScriptData.h"
|
||||
94
src/ScriptData.h
Normal file
94
src/ScriptData.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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 } }
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user