Skip to content

Commit

Permalink
Merge pull request #3 from VeriBlock/feature/update-ctx-tx
Browse files Browse the repository at this point in the history
Implement UpdateContext
  • Loading branch information
Warchant authored Jan 9, 2020
2 parents e6b0b3c + d79f812 commit 35dc4f1
Show file tree
Hide file tree
Showing 29 changed files with 798 additions and 594 deletions.
3 changes: 2 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ VBK_H = \
vbk/pop_service/pop_service_exception.hpp \
vbk/merkle.hpp \
vbk/genesis.hpp \
vbk/entity/publications.hpp \
vbk/entity/pop.hpp \
vbk/interpreter.hpp \
vbk/util.hpp

VBK_GRPC_OUT_ABS = $(srcdir)/vbk/pop_service
Expand Down
4 changes: 3 additions & 1 deletion src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ VBK_TESTS = \
vbk/test/unit/updated_mempool_tests.cpp \
vbk/test/unit/pop_reward_tests.cpp \
vbk/test/unit/vbk_merkle_tests.cpp \
vbk/test/unit/vbk_net_processing_tests.cpp
vbk/test/unit/vbk_net_processing_tests.cpp \
vbk/test/unit/pop_interpreter_tests.cpp \
vbk/test/unit/block_validation_tests.cpp

### VeriBlock section end

Expand Down
1 change: 1 addition & 0 deletions src/consensus/validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ enum class TxValidationResult {
*/
TX_CONFLICT,
TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/RBF/etc limits
TX_BAD_POP_DATA //!< data that is stored inside pop tx is invalid
};

/** A "reason" why a block was invalid, suitable for determining whether the
Expand Down
3 changes: 3 additions & 0 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,9 @@ static bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& s
*/
static bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "") {
switch (state.GetResult()) {
case TxValidationResult::TX_BAD_POP_DATA:
LogPrint(BCLog::NET, "pop tx is invalid: %s\n", message);
break;
case TxValidationResult::TX_RESULT_UNSET:
break;
// The node is providing invalid data:
Expand Down
2 changes: 1 addition & 1 deletion src/script/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&

if (flags & SCRIPT_VERIFY_POP) {
auto& util = VeriBlock::getService<VeriBlock::UtilService>();
return util.EvalScript(script, stack, serror, nullptr);
return util.EvalScript(script, stack, serror, nullptr, nullptr, nullptr, true);
}

if (script.size() > MAX_SCRIPT_SIZE) {
Expand Down
2 changes: 2 additions & 0 deletions src/script/script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ const char* GetOpName(opcodetype opcode)
case OP_CHECKATV : return "OP_CHECKATV";
case OP_CHECKVTB : return "OP_CHECKVTB";
case OP_CHECKPOP : return "OP_CHECKPOP";
case OP_POPBTCHEADER : return "OP_POPBTCHEADER";
case OP_POPVBKHEADER : return "OP_POPVBKHEADER";

case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";

Expand Down
4 changes: 3 additions & 1 deletion src/script/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,14 @@ enum opcodetype
OP_CHECKATV = 0xba,
OP_CHECKVTB = 0xbb,
OP_CHECKPOP = 0xbc,
OP_POPBTCHEADER = 0xbd,
OP_POPVBKHEADER = 0xbe,

OP_INVALIDOPCODE = 0xff,
};

// Maximum value that an opcode can be
static const unsigned int MAX_OPCODE = OP_CHECKPOP;
static const unsigned int MAX_OPCODE = OP_POPVBKHEADER;

const char* GetOpName(opcodetype opcode);

Expand Down
5 changes: 1 addition & 4 deletions src/test/data/script_tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,7 @@
["0", "IF NOP10 ENDIF 1", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "OK",
"Discouraged NOPs are allowed if not executed"],

["0", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "opcodes above MAX_OPCODE invalid if executed"],
["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
["0", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
["0", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
["0", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC", "OK", "opcodes above MAX_OPCODE invalid if executed"],
["0", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
["0", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
["0", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC", "OK"],
Expand Down
3 changes: 2 additions & 1 deletion src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3511,7 +3511,8 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat
// state is already set with error message
return false;
}
// VeriBlock: statefull block validation

// VeriBlock: stateful block validation
if (!VeriBlock::getService<VeriBlock::PopService>().blockPopValidation(block, *pindexPrev, consensusParams, state)) {
return false;
}
Expand Down
7 changes: 6 additions & 1 deletion src/vbk/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ struct Config {
// unique index to this chain; network id across chains
AltchainId index = AltchainId(0x3ae6ca);

uint32_t btc_header_size = 80;
uint32_t vbk_header_size = 64;
uint32_t max_pop_script_size = 150000; // TODO: figure out number
uint32_t max_vtb_size = 100000; // TODO: figure out number
uint32_t min_vtb_size = 1; // TODO: figure out number
Expand All @@ -40,8 +42,11 @@ struct Config {
/// The maximum allowed weight for the PoP transaction
uint32_t max_pop_tx_weight = 150000;

/// The maximun allowed number of PoP transaction in a block
/// The maximum allowed number of PoP transaction in a block
uint32_t max_pop_tx_amount = 50;
/// The maximum allowed number of "UpdateContext" transactions in a block
uint32_t max_update_context_tx_amount = 1;


/////// Pop Rewards section start
uint32_t POP_REWARD_PERCENTAGE = 40;
Expand Down
34 changes: 34 additions & 0 deletions src/vbk/entity/pop.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef INTEGRATION_REFERENCE_BTC_POP_HPP
#define INTEGRATION_REFERENCE_BTC_POP_HPP

#include <cstdint>
#include <vector>

namespace VeriBlock {

using ByteArray = std::vector<uint8_t>;

struct Publications {
ByteArray atv;
std::vector<ByteArray> vtbs;
};

struct Context {
std::vector<ByteArray> btc;
std::vector<ByteArray> vbk;

bool operator==(const Context& other) const
{
return btc == other.btc && vbk == other.vbk;
}
};

enum class PopTxType {
UNKNOWN = 0,
PUBLICATIONS = 1,
CONTEXT = 2
};

} // namespace VeriBlock

#endif //INTEGRATION_REFERENCE_BTC_POP_HPP
18 changes: 0 additions & 18 deletions src/vbk/entity/publications.hpp
Original file line number Diff line number Diff line change
@@ -1,18 +0,0 @@
#ifndef INTEGRATION_REFERENCE_BTC_PUBLICATIONS_HPP
#define INTEGRATION_REFERENCE_BTC_PUBLICATIONS_HPP

#include <stdint.h>
#include <vector>

namespace VeriBlock {

using ByteArray = std::vector<uint8_t>;

struct Publications {
ByteArray atv;
std::vector<ByteArray> vtbs;
};

} // namespace VeriBlock

#endif //INTEGRATION_REFERENCE_BTC_PUBLICATIONS_HPP
212 changes: 212 additions & 0 deletions src/vbk/interpreter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
#ifndef INTEGRATION_REFERENCE_BTC_INTERPRETER_HPP
#define INTEGRATION_REFERENCE_BTC_INTERPRETER_HPP


#include <script/script.h>
#include <script/script_error.h>
#include <vbk/entity/pop.hpp>
#include <vbk/pop_service.hpp>
#include <vbk/service_locator.hpp>

namespace VeriBlock {

namespace {
inline bool set_error(ScriptError* ret, const ScriptError serror)
{
if (ret)
*ret = serror;
return false;
}
typedef std::vector<unsigned char> valtype;

#define stacktop(i) (stack.at(stack.size() + (i)))
inline void popstack(std::vector<valtype>& stack)
{
if (stack.empty())
throw std::runtime_error("popstack(): stack empty");
stack.pop_back();
}

} // namespace

inline bool EvalScriptImpl(const CScript& script, std::vector<std::vector<unsigned char>>& stack, ScriptError* serror, VeriBlock::Publications* publications, VeriBlock::Context* context, PopTxType* type, bool with_checks)
{
CScript::const_iterator pc = script.begin();
CScript::const_iterator pend = script.end();
static const valtype vchFalse(0);
static const valtype vchTrue(1, 1);
opcodetype opcode;
std::vector<unsigned char> vchPushValue;
auto& config = getService<Config>();
auto& pop = getService<PopService>();
Publications pub;
Context ctx;

bool isPublicationsTx = false;
bool isContextTx = false;

if (script.size() > config.max_pop_script_size) {
return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE);
}

try {
while (pc < pend) {
if (!script.GetOp(pc, opcode, vchPushValue)) {
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}

if (!vchPushValue.empty()) {
stack.push_back(vchPushValue);
continue;
}

switch (opcode) {
case OP_POPBTCHEADER: {
// we do not allow single pop tx simultaneously contain publications and context
isContextTx = true;
if (isPublicationsTx) {
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}

const auto& el = stacktop(-1);
if (el.size() != config.btc_header_size) {
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
}

ctx.btc.push_back(el);
popstack(stack);

break;
}
case OP_POPVBKHEADER: {
// we do not allow single pop tx simultaneously contain publications and context
isContextTx = true;
if (isPublicationsTx) {
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}

const auto& el = stacktop(-1);
if (el.size() != config.vbk_header_size) {
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
}

ctx.vbk.push_back(el);
popstack(stack);

break;
}
case OP_CHECKATV: {
// we do not allow single pop tx simultaneously contain publications and context
isPublicationsTx = true;
if (isContextTx) {
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}

// tx has one ATV
if (!pub.atv.empty()) {
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
}

// validate ATV size
const auto& el = stacktop(-1);
if (el.size() > config.max_atv_size || el.size() < config.min_atv_size) {
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
}

// validate ATV content
if (with_checks && !pop.checkATVinternally(el)) {
return set_error(serror, SCRIPT_ERR_VBK_ATVFAIL);
}

pub.atv = el;
popstack(stack);
break;
}
case OP_CHECKVTB: {
// we do not allow single pop tx simultaneously contain publications and context
isPublicationsTx = true;
if (isContextTx) {
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}

// validate VTB size
const auto& el = stacktop(-1);
if (el.size() > config.max_vtb_size || el.size() < config.min_vtb_size) {
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
}

// validate VTB content
if (with_checks && !pop.checkVTBinternally(el)) {
return set_error(serror, SCRIPT_ERR_VBK_VTBFAIL);
}

// tx has many VTBs
pub.vtbs.push_back(el);
popstack(stack);
break;
}
case OP_CHECKPOP: {
// OP_CHECKPOP should be last opcode
if (script.GetOp(pc, opcode, vchPushValue)) {
// we could read next opcode. extra opcodes is an error
return set_error(serror, SCRIPT_ERR_VBK_EXTRA_OPCODE);
}

// stack should be empty at this point
if (!stack.empty()) {
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
}

// we did all checks, put true on stack to signal successful execution
stack.push_back(vchTrue);
break;
}
default:
// forbid any other opcodes in pop transactions
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}
}
} catch (...) {
return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
}

if (isPublicationsTx && pub.atv.empty()) {
// must contain non-empty ATV
return set_error(serror, SCRIPT_ERR_VBK_ATVFAIL);
}

// set return value of publications
if (publications != nullptr) {
*publications = pub;
}

// set return value of context
if (context != nullptr) {
*context = ctx;
}

// set return value of tx type
if (type != nullptr) {
// can not be simultaneously context and publication tx
if (isContextTx && isPublicationsTx) {
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}

if (isContextTx) {
*type = PopTxType::CONTEXT;
} else if (isPublicationsTx) {
*type = PopTxType::PUBLICATIONS;
} else {
*type = PopTxType::UNKNOWN;
return false;
}
}

return true;
}

} // namespace VeriBlock

#undef stacktop

#endif //INTEGRATION_REFERENCE_BTC_INTERPRETER_HPP
Loading

0 comments on commit 35dc4f1

Please sign in to comment.