Skip to content

Instantly share code, notes, and snippets.

@Vishwas1
Last active June 10, 2019 07:09
Show Gist options
  • Save Vishwas1/0bf01f62d4132d090081bc8c70fa8a40 to your computer and use it in GitHub Desktop.
Save Vishwas1/0bf01f62d4132d090081bc8c70fa8a40 to your computer and use it in GitHub Desktop.
Zagg multi node sync problem and possible solutions

Zagg multi node sync problem and possible solutions

Problem :

Zagg multi node sync (for bitcoin blocks) won’t work since we were not making level dbs sync to each other.

  • Setup 2 node zagg network using stellar’s configurations
  • Throw transaction with Account Marker operation (for bitcoin transaction HEX) over one of the node.
  • The operation has to go through validation from Bitcoin code base using doValidate() of the operation.
  • After getting all the operations validated, the transaction goes into mPendingTransaction (which is nothing but memepool for stellar.)
  • After that value is nominated and SCP happens.
  • In the extenalize phase of SCP, the doApply() gets called and block formation happens and stored into leveldb.

Now in case of multi node setup, this wont work since in each phase of SCP the doValidate() method gets called and we know that we SCP can start at any node not necessarily the node where transaction was thrown.

Solutions :

Solution 1

One solution to this problem we can think of is creating an operation for mining the block. In that case the operation will go through the SCP and every node will create those block.

Solution 2

We can make use of --newdb option for creating the blocks (or mining). Now the up side of this is it is easier to implement than the solution1.

Concerns

**One of the major concerns in both of these solutions is, when you create x blocks on both these nodes, will those blocks will be exactly the same or they will be different ? **

I dug into it and found that if you run the generatetoaddress RPC command with same miner’s address (you can set it in config for both these nodes) then the blocks are exactly the same. -- This one have to retest

The other concern we had was, what exactly happens during catch up in stellar? Do they just copy files (from the archival node) or also apply these transaction ?

I debugged the catch up, and found that they not only download the files from the history archives of the other node but also apply these transaction (i.e it closes the ledger), which means that doApply() of operations are also going to get called in catch up.

Next Step

So I am implementing the 2nd solution and will test it. For this I have added two more keys BITCOIN_MINER_ADDRESS and BITCOIN_MINER_BLOCKS apart from eariler added keys (for implementing a new option called --bitcoind with stellar-core command for running the bitcoin along with zagg) BITCOIN_DATADIR and BITCOIN_REGTEST in the stellar-core.cfg file.

## Bitcoin related configs
# To run bitcoin in regtest mode. default is true
BITCOIN_REGTEST=true
# Specify the datadirectory for bitcoin. default is /home/$user/.bitcoin
BITCOIN_DATADIR="/home/vishswasb/zagg/node01/"
# Miner public key
BITCOIN_MINER_ADDRESS="2Mtznvnp8P6CnDH6BQyjFCbRTpMq2XHzV3D"
# Number of blocks to be generated: this parameter will be used at the time of --newdb
# Default value is 101
BITCOIN_MINER_BLOCKS=101

Now what will happen is, all nodes will be initialized with same blocks and at the time of SCP validation they will not fail. Also in case if any node fell down, then at the time of catch up the ledger will close and form the blocks with operation’s HEX value.

Here and here is the implementation of block formation at the time of --newdb.

Tests

Stellar Features test

  • Setup a 2 zagg node network without bitcoind making both these nodes validators each other. Keep it running for sometime.
  • Drop the first node
  • Re-join the network and see if it is catching up properly

Zagg Features test

  • Now run the 2 node network with --bitcoind option

Test 1

Check after doing --newdb in both these nodes that each of bitcoin folders has same blocks (match with blockhashes for the confirmation)

Test 2

Form a bitcoin transaction and send over one of these node, wait for ledger to close -> see if the block formation is happening in both of the nodes.

Test 3

Pull down one of these node -> Let the other node running and do bitcoin transaction over one of the operation -> bring up the 1st node and see if it catching up -> check the blocksize and formation in the 1st node.

Date : 3 June 2018

Mistake: The mistake which I was doing is, I assumed that mine block action will happen at all the nodes. But I was wrong. Only one block will mine (with coinbase) and broadcast the block to the other and the other block will just validate and accept that block.

How will it work?

2 Operations :

  • MineBlockOp opeartion
  • SheildPaymentOp opeartion (as of now we will use accountMarker for this)

MineBlockOp Operation (Account to UTXO)

This operation can be used to mine blocks for passed miner account.

struct MineBlockOp
{
    string32<32> minerAccount; // account to be mine. this is noting but sender's bitcoin address.
    string64<32> block; //INTERNAL:this is hidden for wallet UI and will  be filled once the block gets formed during the op. Its string since its going to be HEX-encoded block.
    // int64 nBlock; //INTERNAL: number of blocks - we will fix it for 1 as of now
    int64 amount; // corresponding utxo amount that needs to be converted 
};

block [ coinbase]

In the stellar wallet, user only has to pass minerAccount value and amount which he wants to withdraw (convert stellar account amount to utxos) for MineBlockOp operation. nBlock is set to 1 by default (as of now). User need not to pass values for block and nBlock. These are the internal fields and used by stellar-core.

  • the code validates the minerAccount value (if it is proper bitcoin address?)
  • forms the block (calls createBlock() in bitcoin code base)
  • but the block would not be stored into the bitcoin database.
  • set MineBlockOp.block = block
  • set MineBlockOp.nBlock = 1

doValid()

This method gets called before tx goes into the mempool and during the every phase of SCP.

  • validates the MineBlockOp.block value

doApply()

At the time of ledger close:

  • doApply() gets called
  • store MineBlockOp.block into bitcoin database
    • We can make use of submitBlock RPC for this purspose which accepts block HEX as paramter. It validates, stores and broadcast the block to the peers. We can skip the broadcasting part.
  • all nodes will do the same and every nodes's bitcoin db will have same block.

SheildPaymentOp Operation (UTXO to UTXO)

This is basically the Bitcoin transaction operation we will have to use. It accepts bitcoin HEX.

struct SheildPaymentOp
{
    string32<32> hex; // bitcoin transaction hex
    string64<32> block; //INTERNAL: this is hidden for wallet UI and will  be filled once the block gets formed during the operation. Its string since its going to be HEX-encoded block
};

block [ coinbase (miner = sender, amount = 0),hex ]

Again user have to pass the hex only not the block value and will be filled later. Now this new block will be mined for the sender's bitcoin address and amount(or fee) = 0.

  • call bitcoin code base to validate HEX.
  • forms the block (calls createBlock() in bitcoin code base)
  • but the block would not be stored into the bitcoin database.
  • set SheildPaymentOp.block = block

doValid()

  • validates the SheildPaymentOp.block value : this is block HEX
  • First the block HEX is decoded into block data st. using DecodeHexBlk. It returns object of type CBlock.
  • Use CheckBlock() for validation of block, which accepts parameter of type CBlock.

doApply()

  • store SheildPaymentOp.block into bitcoin database
  • First the block HEX is decoded into block data st. using DecodeHexBlk. It returns object of type CBlock.
  • Use AcceptBlock() to add block into the db. which accepts paramter of type CBlock shared Pointer.

BurnOp Operation (burn utxo)

  • Send UTXOs to a bogus address
  • Or else use OP_RETURN

https://medium.com/@alcio/how-to-destroy-bitcoins-255bb6f2142e

Date : 4 June 2019

  1. Problem Statement.
  2. Solution.
  3. Implementation

PROBLEM STATEMENT

The bigger picture is to do two types of transaction on the Zagg network. Also to perform two funtionalites on the network Withdrwal and Deposite.

Types Of Account

a) unshielded tx (using account) :Stellar payment	
b) shielded tx (using utxo) : First get converted to UTXO -> UTXO goes Zero knowledger -> UTXO gets transfer to the reciepit -> UTxo to Recipent's steallar account

SOLUTION

Performing unshield transaction

simple payment operation on stellar.

Performing shield transaction

The solution for shielded transaction involves analogy of withdrawing money (utxo) from his stellar account and depositing money (utxo) back to stellar accout after performing the transaction (utxo to utxo). Every person has two types of account (public-private key pairs): a) stellar account b) bitcoin account. Suppose a Person A wants to do the shield transaction of say Aamt=10 to person B.

Person A
	: Stellar Account (As): amount_As = 100
	: Bitcoin Account (Ab): amount_Ab = 0 

Person B
	: Stellar Account (Bs): amount_Bs = 0
	: Bitcoin Account (Bb): amount_Bb = 0 

Account to UXTO conversion (withdrawal)

  • Step 1: First person A needs to perform MineBlockOp operation in order to withdraw some money (of Aamt) to his bitcoin account (Ab) from stellar account (As).
	1. check if Aamt > amount_Ab : he already has sufficient utxos
	go to step 2 else go to 5
	2. check if Aamt > amount_As
	go to throw error else go to 3
	3. the miner account = Ab
	4. amount =  Aamt
	5. exit
  • Step 2: Now that he has withdrawn some money from his stellar's account, that much of value needs to be deducted from his account. To do that we have to perform a paymentOp operation from As to root account worth of Aamt.

Note:

  • He can perform both the operations in one transaction.
  • He may skip the step 1 since he already has some balance in his bitcoin's address if he wants to.
  • You can not persform Step 2 with out having to perform Step 1 in case you do not have sufficient UTXOs. If done the whole tranaction would fail.
  • In this operation, basically he is sending money from one of his account(stellar) to another (bitcoin), which is why this called withdrawal

Shield Transaction (UTXO to UTXO)

Once person A has sufficient amount of UTXOs , he can send these UTXO to Person B by performing SheildPaymentOp operation. Here he will have to pass the HEX where sender's address would be bitcoin address of Person A and receiver's address is Bitcoin address of Person B. This transaction is shielded since we will use Zero Knowledge Proof.

  • Then he will do SheildPaymentOp (bitcoin transaction)
    • HEX (sender = Ab, receiver = Bb, amount = Aamt)

UXTO to Account (deposite)

Once the SheildPaymentOp operation is performed, person A or person B can deposite his UTXO into their respective stellar's account by burning utxos.

  • Bb will burn Aamt utxo : burnOp
  • Ask root account to send Aamt XLM to Bs : paymentOp

IMPLEMENTATION

  1. MineBlockOp Operation (Account to UTXO)
  2. SheildPaymentOp Operation (UTXO to UTXO)
  3. BurnOp - working on it.

https://docs.google.com/drawings/d/1z0LFOC_UYh8h9aq423wFFl8gD7aASTZGmcMWyCNsWkQ/edit?ts=5cf64ab6

@Vishwas1
Copy link
Author

Sri discussion points :

  1. Do not do any engineering/optimisation work for now (no unifying db)
  2. Replace bitcoin with zChash work now without adding much complexity (edited)
  3. Look into JPMorgan chase zero knowledge proof
  4. think about double spending problem in case of SheildPaymentOp operation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment