The fifth chapter to write himself of Bitcoin transactions relay

Overview

In the previous chapter, we give a trade journal, you must own hand once mining, the transaction will be added to a block inside. In this chapter, we will introduce a relay mechanism pending transaction. Once you have this mechanism, we want to deal, you do not need to do it yourself mining, but will be sent to our own trading network to block chain (concept that is relayed) by the other node after mining, our transaction record to the new block they dug to go. Where these transactions are called "pending transactions." A typical example is when a user wants to initiate a transaction (to send a certain number of coins to the specified address), he would deal a broadcast to the entire network, and hope that other miners put the transaction into the area to block.

For an encryption monetary system, this dysfunction is important. Because that would mean we do not need to be a deal because while they were mining in order to save on transaction records. This will greatly improve efficiency. After all, such as Bitcoin, like the time of the transfer at any time, to dig a mine it is more and more difficult. If we, the family did not mine (mining machine) Some users want others Bitcoin transaction, but also their own dig mines, and that the transaction would not know what month can be reached.

In order to achieve broadcast to other nodes and purpose, and the first chapter will be synchronized broadcast and synchronized blocks, we need to "pending transaction" should be broadcast. In other words, we block chain system now contains the following broadcast and synchronization:

  • Block chain (ie block chain and included in the block of "res judicata transaction" record)
  • Pending transaction (also not included in the transaction of any block)

The complete code in this section, please see here

Trading pool

Since our trade now is not carried out by its own mining recorded immediately after its creation, then we need to record these transactions in order to broadcast to other miners. We will save local pending transaction called "trading pits" in Bitcoin system, also known as mempool.

In fact, our pool is trading in a storage node data structure for all "pending transaction", in order to achieve simplicity, we here be designed as a list of "transaction" consisting of data (if you do not remember what the structure of long transactions kind, please look at the previous section record):

let transactionPool: Transaction[] = [];

Of course, the order and / mindTransaction entrance area after mining transactions must separate yourself, we provide another interface for trading with only POST / sendTransaction . After calling this method, we will create a node sum of new transactions in our local pool based on the previous trading mechanism wallet. After that we will conduct this interface as the priority use of a trade transaction interface.

app.post('/sendTransaction', (req, res) => {
        ...
    })

Create a transaction process and Chapter IV process similar to that described, a little bit difference is that when the transaction is created, we will incorporate the transaction to our trading pool, rather than immediately carry out mining record.

broadcast

Whole "pending transaction] idea was to spread to the entire block these transactions online chain, so that some nodes will eventually be" dig "to block the chain to go. To achieve this goal, we must first of these pending transactions dissemination establish some simple network rules:

  • When a node receives a broadcast to others out of trading pits, and found himself had not seen "] pending transaction record, the node will have never seen these records into your own trading pool, then their trading pits to broadcast out
  • When establishing a connection point node and other nodes will request a complete transaction record keeping of the other pool to the target node

Similar radio and synchronization block chain, we need to build two new message types simultaneously broadcast service for our pending transaction pool: QUERY_TRANSACTION_POOL and RESPONSE_TRANSACTION_POOL . Our final message type data structure is shown below:

enum MessageType {
    QUERY_LATEST = 0,
    QUERY_ALL = 1,
    RESPONSE_BLOCKCHAIN = 2,
    QUERY_TRANSACTION_POOL = 3,
    RESPONSE_TRANSACTION_POOL = 4
}

Trading broadcast request data pool will eventually be created in the following ways:

const responseTransactionPoolMsg = (): Message => ({
    'type': MessageType.RESPONSE_TRANSACTION_POOL,
    'data': JSON.stringify(getTransactionPool())
}); 

const queryTransactionPoolMsg = (): Message => ({
    'type': MessageType.QUERY_TRANSACTION_POOL,
    'data': null
});

When a node receives RESPONSE_TRANSACTION_POOL after this broadcast, we need to have appropriate response to the request code logic. Whenever we receive broadcast over the pending transaction pool, we will try to add to our local deals to the pool. Of course, we need to do the appropriate check on the inside of transactions. Only those transactions (not on our list of share trading pits locally saved in) we had not seen before, and effective transaction, we have to include it into our trading pool. Followed, as described above, we will give our trading pool broadcasted, in order to achieve full network synchronization:

case MessageType.RESPONSE_TRANSACTION_POOL:
    const receivedTransactions: Transaction[] = JSONToObject<Transaction[]>(message.data);
    receivedTransactions.forEach((transaction: Transaction) => {
        try {
            handleReceivedTransaction(transaction);
            //if no error is thrown, transaction was indeed added to the pool
            //let's broadcast transaction pool
            broadCastTransactionPool();
        } catch (e) {
            //unconfirmed transaction not valid (we probably already have it in our pool)
        }
    });

Pending transaction validation

Because the pending transaction data is broadcast over the unpredictable, we need these data are known as pending transactions carried out validation. Check the validity of the transactions we had achieved will still spend, such as checking the data is formatted correctly, you input the transaction, outputs and the signature must be the same (ie validateTxIn function described in the previous section, is simply for each transaction each input, output deal with sources pointed to the address as the public key to decrypt the signature input, and check whether the transaction id and the same, in order to verify the transaction referenced in the source input indeed belong to all users. because only the public the user's key is to properly decrypt the transaction signature, which proves the owner of the source of the transaction really is the originator of the transaction).

const validateTxIn = (txIn: TxIn, transaction: Transaction, aUnspentTxOuts: UnspentTxOut[]): boolean => {
    const referencedUTxOut: UnspentTxOut =
        aUnspentTxOuts.find((uTxO) => uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex);
    if (referencedUTxOut == null) {
        console.log('referenced txOut not found: ' + JSON.stringify(txIn));
        return false;
    }
    const address = referencedUTxOut.address;

    const key = ec.keyFromPublic(address, 'hex');
    const validSignature: boolean = key.verify(transaction.id, txIn.signature);
    if (!validSignature) {
        console.log('invalid txIn signature: %s txId: %s address: %s', txIn.signature, transaction.id, referencedUTxOut.address);
        return false;
    }
    return true;
};

In addition to these existing rules, we also need to add a new rule: If a transaction is used to refer to any source of input currency transactions in the current pending transaction pool already exists, then the transaction will be considered invalid transaction does not go into the trading pool.

const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): boolean => {
    const txPoolIns: TxIn[] = getTxPoolIns(aTtransactionPool);

    const containsTxIn = (txIns: TxIn[], txIn: TxIn) => {
        return _.find(txPoolIns, (txPoolIn => {
            return txIn.txOutIndex === txPoolIn.txOutIndex && txIn.txOutId === txPoolIn.txOutId;
        }))
    };

    for (const txIn of tx.txIns) {
        if (containsTxIn(txPoolIns, txIn)) {
            console.log('txIn already found in the txPool');
            return false;
        }
    }
    return true;
};

There is no explicit definition will be removed from trading operations pending transaction pool, current practice is that every time the network to produce a new block, will at the same time to update the trading pits.

Accounting

Next we want to achieve the appropriate logic node will make a pending transaction record to a pool dug in their new block to (under normal circumstances, help accounting node should receive a reward, but we are here and not achieved). The whole logic is simple: when a node dug a block, then mining will get the original transaction and our trading pits dug packaged together into a new block to go.

const generateNextBlock = () => {
    const coinbaseTx: Transaction = getCoinbaseTransaction(getPublicFromWallet(), getLatestBlock().index + 1);
    const blockData: Transaction[] = [coinbaseTx].concat(getTransactionPool());
    return generateRawNextBlock(blockData);
};

Since the trading pits at the time had received RESPONSE_TRANSACTION_POOL broadcast verification has been done, so we are here does not require any validation work.

Pool trading update

Once dug a new block, our pending transaction is likely to be accounting together with the new block to block in the chain, the pending transaction will become res transaction. That is, each new block carry trades are likely to lead to our pending transaction pool is no longer valid. For example, the following:

  • A pen pending transaction by the pool is accounting to the new block (possibly originating node traded in mind when mining their own, there may be other nodes remember)
  • Pending transaction input sources pointed to currency trading, is the originator of the transaction to the consumer other out

These will lead to failure of our trading pool. Trading pool is ineffective, however, as we have explained the first two chapters, we have been keeping an updated list of "non-consumer transactions outpus", so we just use the list as the cornerstone of all the input transactions pool is not exist in terms of "consumer transaction outupts not" removed out on the line. Logic in the code as follows:

const updateTransactionPool = (unspentTxOuts: UnspentTxOut[]) => {
    const invalidTxs = [];
    for (const tx of transactionPool) {
        for (const txIn of tx.txIns) {
            if (!hasTxIn(txIn, unspentTxOuts)) {
                invalidTxs.push(tx);
                break;
            }
        }
    }
    if (invalidTxs.length > 0) {
        console.log('removing the following transactions from txPool: %s', JSON.stringify(invalidTxs));
        transactionPool = _.without(transactionPool, ...invalidTxs)
    }
};

Experience

Start two nodes (at the recommended two command line terminal)

npm run node1
npm run node2

Check node address wallet

By a postman, and 3001 are transmitted to the request / address of the access point 3002 to acquire two addresses of the two ports wallet, such as the node. 1: the GET HTTP: // localhost: 3001 / address

{
    "address": "04d4d57026bd7b0d951b8d6c72ed9118004cd0929d10f94d7c41b24dbe9d84fa3bb389f2525c05a46bd8d1203b4b3c0e3499f30e5a55f84c573fcccd94c83bc13a"
}

Mining

A mining node 2, to obtain 50 credits. The following data POST to http: // localhost: 3002 / mineBlock Interface:

{
    "data": "Some data from node2"
}

Returns the following:

{
    "index": 1,
    "previousHash": "91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627",
    "timestamp": 1561004915,
    "data": [
        {
            "txIns": [
                {
                    "signature": "",
                    "txOutId": "",
                    "txOutIndex": 1
                }
            ],
            "txOuts": [
                {
                    "address": "04bdc45ca144a5e5c8d0b03443f9aedfc8260d4665ac3fd41bd9eb2f06e4dc8228be1e14a4938837cada904cc81fc5747930f480d4d7888b5e82aac6f0581be0df",
                    "amount": 50
                }
            ],
            "id": "46dc195f7d44c2c1687fbd67a9a40263fd508067f89d8c07ee0e14826394b1d5"
        }
    ],
    "hash": "ca7eff56caf46b90cd7230a7c5684e1c201da48b7293aa282efebca2fabf0792",
    "difficulty": 0,
    "nonce": 0
}

View transactions outputs unconsumed

Because the global trading outputs consumption is not the whole network synchronized, so no matter which node to see, the results are the same. Here at node 1, for example, Get the following interfaces: HTTP: // localhost: 3001 / unspentTransactionOutputs

Returns the following:

[
    {
        "txOutId": "e655f6a5f26dc9b4cac6e46f52336428287759cf81ef5ff10854f69d68f43fa3",
        "txOutIndex": 0,
        "address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a",
        "amount": 50
    },
    {
        "txOutId": "46dc195f7d44c2c1687fbd67a9a40263fd508067f89d8c07ee0e14826394b1d5",
        "txOutIndex": 0,
        "address": "04bdc45ca144a5e5c8d0b03443f9aedfc8260d4665ac3fd41bd9eb2f06e4dc8228be1e14a4938837cada904cc81fc5747930f480d4d7888b5e82aac6f0581be0df",
        "amount": 50
    }
]

2 mining excitation can see the resulting node id of "46dc195f7d44c2c1687fbd67a9a40263fd508067f89d8c07ee0e14826394b1d5" has been placed in the non-consumer transactions outputs, while a transaction is created automatically generated when the original transaction system startup, and leave.

View node does not own the consumer outputs

In addition, to facilitate our experience, the system has a total of another interfaces that allow us to view the corresponding node is not owned by the consumer outputs. For example, we can send Get to the interface http: // localhost: 3002 / myUnspentTransactionOutputs not to acquire the consumer outputs a list of node 2. Returns the following

[
    {
        "txOutId": "46dc195f7d44c2c1687fbd67a9a40263fd508067f89d8c07ee0e14826394b1d5",
        "txOutIndex": 0,
        "address": "04bdc45ca144a5e5c8d0b03443f9aedfc8260d4665ac3fd41bd9eb2f06e4dc8228be1e14a4938837cada904cc81fc5747930f480d4d7888b5e82aac6f0581be0df",
        "amount": 50
    }
]

Initiate a transaction

Node 2 transmits 30 credits to node 1 wallet. The following transaction data POST to http: // localhost: 3002 / sendTransaction interface.

{
    "address": "04d4d57026bd7b0d951b8d6c72ed9118004cd0929d10f94d7c41b24dbe9d84fa3bb389f2525c05a46bd8d1203b4b3c0e3499f30e5a55f84c573fcccd94c83bc13a",
    "amount": 30
}

Returns the following:

{
    "txIns": [
        {
            "txOutId": "46dc195f7d44c2c1687fbd67a9a40263fd508067f89d8c07ee0e14826394b1d5",
            "txOutIndex": 0,
            "signature": "30450220130a2d3283337bb3721b992538ba19bbe6561376d0ddc9572595c0af8fb487d502210095d7cfe26717204329e22a386c274ec45d09190f1089fc354ad726ba375d917b"
        }
    ],
    "txOuts": [
        {
            "address": "04d4d57026bd7b0d951b8d6c72ed9118004cd0929d10f94d7c41b24dbe9d84fa3bb389f2525c05a46bd8d1203b4b3c0e3499f30e5a55f84c573fcccd94c83bc13a",
            "amount": 30
        },
        {
            "address": "04bdc45ca144a5e5c8d0b03443f9aedfc8260d4665ac3fd41bd9eb2f06e4dc8228be1e14a4938837cada904cc81fc5747930f480d4d7888b5e82aac6f0581be0df",
            "amount": 20
        }
    ],
    "id": "a4089fb337943eb80f381f107bdc1583c9b282e6cf735751d976ebd2125c5183"
}

At this view not block chain and consumption outputs, we can see that in fact the deal has not been added to the block chain, it has not been consumed.

Node 1 mining and accounting

Then if any one node mining, will be the node 2 transactions initiated to record the new block to go. For example node 1 mining, POST data to the http: // localhost: 3001 / mineBlock

{
    "data": "Some data from node1"
}

Returned can be seen from the record, the new transaction record block, in addition to recording 50 obtained mining incentive credits, the above transactions initiated by the node 2 also to block the journal

{
    "index": 2,
    "previousHash": "ca7eff56caf46b90cd7230a7c5684e1c201da48b7293aa282efebca2fabf0792",
    "timestamp": 1561007564,
    "data": [
        {
            "txIns": [
                {
                    "signature": "",
                    "txOutId": "",
                    "txOutIndex": 2
                }
            ],
            "txOuts": [
                {
                    "address": "04d4d57026bd7b0d951b8d6c72ed9118004cd0929d10f94d7c41b24dbe9d84fa3bb389f2525c05a46bd8d1203b4b3c0e3499f30e5a55f84c573fcccd94c83bc13a",
                    "amount": 50
                }
            ],
            "id": "2e668dcd87fb900f346bab921a8349bc0e39d560c5a07a727cc9484aff471303"
        },
        {
            "txIns": [
                {
                    "txOutId": "46dc195f7d44c2c1687fbd67a9a40263fd508067f89d8c07ee0e14826394b1d5",
                    "txOutIndex": 0,
                    "signature": "30450220130a2d3283337bb3721b992538ba19bbe6561376d0ddc9572595c0af8fb487d502210095d7cfe26717204329e22a386c274ec45d09190f1089fc354ad726ba375d917b"
                }
            ],
            "txOuts": [
                {
                    "address": "04d4d57026bd7b0d951b8d6c72ed9118004cd0929d10f94d7c41b24dbe9d84fa3bb389f2525c05a46bd8d1203b4b3c0e3499f30e5a55f84c573fcccd94c83bc13a",
                    "amount": 30
                },
                {
                    "address": "04bdc45ca144a5e5c8d0b03443f9aedfc8260d4665ac3fd41bd9eb2f06e4dc8228be1e14a4938837cada904cc81fc5747930f480d4d7888b5e82aac6f0581be0df",
                    "amount": 20
                }
            ],
            "id": "a4089fb337943eb80f381f107bdc1583c9b282e6cf735751d976ebd2125c5183"
        }
    ],
    "hash": "c245d2d2f9f1ec050b085fd2be39b3cd51e5af6bb53158297276d9b0b17c2b61",
    "difficulty": 0,
    "nonce": 0
}

View pending transaction pool

Then we'll see a pending transaction pool, you will find that the transaction has been updated removed out

[]

View node of the pending transaction outputs 2

Then if we see a pending transaction node outputs 2, you will find yourself on the remaining 20 coins.

[
    {
        "txOutId": "a4089fb337943eb80f381f107bdc1583c9b282e6cf735751d976ebd2125c5183",
        "txOutIndex": 1,
        "address": "04bdc45ca144a5e5c8d0b03443f9aedfc8260d4665ac3fd41bd9eb2f06e4dc8228be1e14a4938837cada904cc81fc5747930f480d4d7888b5e82aac6f0581be0df",
        "amount": 20
    }
]

summary

By introducing "pending transaction pool" mechanism, we now no longer need to own mining to conduct a transaction, other nodes can also help us to billing. But, as mentioned earlier, accounting for helping us node and will not receive any incentive, because our system does not have to implement transaction processing functions.

The next chapter we will achieve a UI interface to facilitate the use of the wallet and the block chain operation.

Chapter Six

This article compiled by the World Council Fenduo Zhuhai, Reprinted with authorization, like a point like, please comment Tucao, such as the project on Github give to the stars, will be greatly appreciated.

Guess you like

Origin www.cnblogs.com/techgogogo/p/11072558.html
Recommended