To create an iterable blockchain, which could work with an extendable transaction class. Here the link GitHub repo!
base_transaction class.block class with Transaction and HashFunction templates.blockchain class with the same templates and custom iterators to make it iterable.Lets Setup the extra files!
Create a includes folder and add files from Github
not_implemented_exception: The exception that is thrown when a requested method or operation is not implemented.class not_implemented_exception : public logic_error
{
public:
not_implemented_exception(
string function = __builtin_FUNCTION()
) : logic_error("`" + function + "` not implemented!"){};
};
base_transaction<EncryptionAlgo>Here are the required things:
from_addr, to_addr, transfer_amountgenerate_hash_input)string Operator (for string type casting)<< Operator (for cout)< Operator (for comparison)get_balance(addr))sign_transaction(key_pair))is_transaction_valid(verifying_func))Every Function logic will be same, which is to throw not_implemented_exception, for example:
operator string() const {throw not_implemented_exception();}
custom_transaction : public base_transaction<EncryptionAlgo>Private Members:
from_address (Yours public_key)to_address (Others public_key)transfer_amounttimestampsignature (Initially 0, will be updated in sign_transaction)Public Members:
from_addr, to_addr, transfer_amountcustom_transaction(from_adrr, to_addr, amount){
from_address = from_addr;
to_address = to_addr;
transfer_amount = amount;
timestamp = chrono::steady_clock::now();
signature = 0;
}
generate_hash_input)# Concatenation of all stringified private variables (except Signature)
# to_string(...) in C++
return (str(from_addr) + str(to_addr) + str(amount) + str(timestamp))
string Operator (for string typecasting)operator string() const
{
string from_address_str = "\nfrom_address: " + to_string(from_address);
string to_address_str = "\nto_address: " + to_string(to_address);
string transfer_amount_str = "\ntransfer_amount: " + to_string(transfer_amount);
string signature_str = "\nsignature: " + to_string(signature);
return from_address_str + to_address_str + transfer_amount_str + signature_str;
}
<< Operator (for cout)friend ostream &operator<<(ostream &out, custom_transaction const &temp)
{
// Using above string operator
return out << string(temp);
}
< Operator (for comparison)bool operator<(const custom_transaction &other) const
{
return generate_hash_input() < other.generate_hash_input();
}
get_balance(addr))float get_balance(addr) const
{
if (addr == to_address)
return transfer_amount;
if (addr == from_address)
return -transfer_amount;
return 0;
}
sign_transaction(key_pair))Here are some Pointers regarding signing
from_address should match public_key in key_pair. Let us create an Error Regarding that:
class public_key_mismatch : public invalid_argument
{
public:
public_key_mismatch(
string addr, std::string pk) : invalid_argument("from_addr: '" + addr + "' do not match public_key: '" + pk + "'"){};
};
class resign_transaction_exception : public logic_error
{
public:
resign_transaction_exception(string transaction) : logic_error("Resigning Transaction!" + transaction){};
};
generate_hash_input()
template <typename EncryptionAlgo>
bool sign_transaction(EncryptionAlgo key_pair)
{
if (from_address != key_pair.get_public_key())
throw public_key_mismatch(to_string(from_address), to_string(key_pair.get_public_key()));
if (signature != 0) // already signed
throw resign_transaction_exception(*this);
signature = key_pair.sign(generate_hash_input());
return true;
}
is_transaction_valid(verifying_func))bool is_transaction_valid(bool (*verfication_function)(string, size_t, address)) const
{
// reward, since reward is given by admin, there is no key pair
if (from_address == 0)
return true;
return verfication_function(generate_hash_input(), signature, from_address);
}
block <Transaction, HashFunctionClass>NOTES:
nonce (“number used once”) a 32-bit, data computed in proof-of-workhash_function is an instance of template class used for all hashing related needs (std::hash used in main.cpp)
# Here `nonce` is found via brute force
# until HASH_PATTERNis matched.
while(1):
hash_input = str(...) + str(nonce)
if re.match(hash_function(hash_input), HASH_PATTERN):
return nonce
nonce += 1
sha256n zeros, higher the n, harder to compute.namespace::ra :
std::hash<string> for reference)15/n, lesser the n, harder to compute.block_chain <Transaction, HashFunctionClass>Well as the name states it is a chain of blocks, So Naturally, It will contain the same Template Arguments as Block
Private Members:
list<BlockType> chain (A list of blocks)list<Trasaction> pending_transaction (Temperaroy Buffer before mining (create a block and adding it to list))difficulty (to be passed in block class)minning_reward (If exists, will add a new transaction from admin before mining block)verfication_function (to verify block or transaction itself)Public Members:
Iterator Class (To make iteration easy)
std::_List_iterator<block_type> block_ptr,==, !=, ++, &++, --, &--, for example:iterator operator--(int)
{
iterator _temp = *this;
m_block_ptr--;
return _temp;
}
const iterator begin() { return chain.begin(); }
const iterator end() { return chain.end(); }
block_type &back() { return chain.back(); }
block_type &front() { return chain.front(); }
int size() { return chain.size(); }
block_chain(diffuculty, verfication_function, minning_reward) Constructor:
float balance = 0block_chain from begin() to end() using iterator class and add it to balancebalanceadd_transaction(temp)
temp using is_transaction_valid by passing in verfication_functionpending_transaction else Throw Errormine_pending_transactions(minning_reward_address)
minning_reward exsits, add a reward transaction to minning_reward_address, else continuepending_transaction, and push it to chain.pending_transaction.is_chain_valid()
chain, check the validity of current block using is_block_valid by passing in verfication_functionprevious_hash of current block matches hash of the previous block