Merge branches 'consensus-forking' (pull #615) and 'byte-order' (pull #583)

This commit is contained in:
David A. Harding 2014-10-25 14:56:31 -04:00
commit d5900e3df4
No known key found for this signature in database
GPG key ID: 4B29C30FF29EC4B7
14 changed files with 571 additions and 11 deletions

View file

@ -48,6 +48,8 @@ confirmed:
confirmation: confirmation:
confirmations: confirmations:
confirmed transactions: confirmed transactions:
consensus:
consensus rules:
denomination: denomination:
denominations: denomination denominations: denomination
DER format: der DER format: der
@ -65,8 +67,11 @@ extended keys: extended key
extended private key: extended private key:
extended public key: extended public key:
fiat: fiat:
fork: accidental fork fork:
forks: fork
genesis block: genesis block:
hard fork:
hard forks: hard fork
hardened extended private key: hardened extended private key:
HD protocol: HD protocol:
header nonce: header nonce:
@ -76,6 +81,7 @@ inputs: input
input: input:
intermediate certificate: intermediate certificate:
intermediate certificates: intermediate certificate intermediate certificates: intermediate certificate
internal byte order:
key index: key index:
key pair: key pair:
'`label`': label '`label`': label
@ -165,6 +171,7 @@ root certificate:
root seed: root seed:
RPCs: rpc RPCs: rpc
RPC: RPC:
RPC byte order:
satoshi: satoshi:
satoshis: satoshi satoshis: satoshi
'`script`': pp script '`script`': pp script
@ -184,6 +191,8 @@ signature hash:
signature script: signature script:
signature scripts: signature script signature scripts: signature script
signatures: signature signatures: signature
soft fork:
soft forks: soft fork
SPV: SPV:
stack: stack:
stale block: stale block:
@ -217,10 +226,14 @@ wallet import format:
x.509: x509 x.509: x509
X509Certificates: X509Certificates:
## BIPS in numerical order; don't use padding zeros (e.g. BIP70 not BIP0070) ## BIPs in numerical order; don't use padding zeros (e.g. BIP70 not BIP0070)
BIP16:
BIP21: BIP21:
BIP30:
BIP32: BIP32:
BIP34:
BIP39: BIP39:
BIP50:
BIP70: BIP70:
BIP71: BIP71:
BIP72: BIP72:

View file

@ -4,8 +4,15 @@
The block chain provides Bitcoin's public ledger, an ordered and timestamped record The block chain provides Bitcoin's public ledger, an ordered and timestamped record
of transactions. This system is used to protect against double spending of transactions. This system is used to protect against double spending
and modification of previous transaction records, using proof of and modification of previous transaction records.
work verified by the peer-to-peer network to maintain a global consensus.
Each full node in the Bitcoin network independently stores a block chain
containing only blocks validated by that node. When several nodes all
have the same blocks in their block chain, they are considered to be in
[consensus][]{:#term-consensus}{:.term}. The validation rules these
nodes follow to maintain consensus are called [consensus
rules][]{:#term-consensus-rules}{:.term}. This section describes many of
the consensus rules used by Bitcoin Core.
{% endautocrossref %} {% endautocrossref %}
@ -148,7 +155,7 @@ block 2016 is where difficulty could have first been adjusted.
Multiple blocks can all have the same block height, as is common when Multiple blocks can all have the same block height, as is common when
two or more miners each produce a block at roughly the same time. This two or more miners each produce a block at roughly the same time. This
creates an apparent [fork][accidental fork]{:#term-accidental-fork}{:.term} in the block chain, as shown in the creates an apparent [fork][]{:#term-fork}{:.term} in the block chain, as shown in the
illustration above. illustration above.
When miners produce simultaneous blocks at the end of the block chain, each When miners produce simultaneous blocks at the end of the block chain, each
@ -244,3 +251,104 @@ Since it is impractical to have separate transactions with identical txids, this
otherwise, a valid block with the duplicates eliminated could have the same merkle root and block hash, but be rejected by the cached invalid outcome, resulting in security bugs such as CVE-2012-2459. otherwise, a valid block with the duplicates eliminated could have the same merkle root and block hash, but be rejected by the cached invalid outcome, resulting in security bugs such as CVE-2012-2459.
{% endautocrossref %} {% endautocrossref %}
### Consensus Rule Changes
{% autocrossref %}
To maintain consensus, all full nodes validate blocks using the same
consensus rules. However, sometimes the consensus rules are changed to
introduce new features or prevent network abuse. When the new rules are
implemented, there will likely be a period of time when non-upgraded
nodes follow the old rules and upgraded nodes follow the new rules,
creating two possible ways consensus can break:
1. A block following the new consensus rules is accepted by upgraded
nodes but rejected by non-upgraded nodes. For example, a new
transaction feature is used within a block: upgraded nodes understand
the feature and accept it, but non-upgraded nodes reject it because
it violates the old rules.
2. A block violating the new consensus rules is rejected by upgraded
nodes but accepted by non-upgraded nodes. For example, an abusive
transaction feature is used within a block: upgraded nodes reject it
because it violates the new rules, but non-upgraded nodes accept it
because it follows the old rules.
In the first case, rejection by non-upgraded nodes, mining software
which gets block chain data from those non-upgraded nodes refuses to
build on the same chain as mining software getting data from upgraded
nodes. This creates permanently divergent chains---one for non-upgraded
nodes and one for upgraded nodes---called a [hard
fork][]{:#term-hard-fork}{:.term}.
![Hard Fork](/img/dev/en-hard-fork.svg)
In the second case, rejection by upgraded nodes, it's possible to keep
the block chain from permanently diverging if upgraded nodes control a
majority of the hash rate. That's because, in this case, non-upgraded
nodes will accept as valid all the same blocks as upgraded nodes, so the
upgraded nodes can build a stronger chain that the non-upgraded nodes
will accept as the best valid block chain. This is called a [soft
fork][]{:#term-soft-fork}{:.term}.
![Soft Fork](/img/dev/en-soft-fork.svg)
Although a fork is an actual divergence in block chains, changes to the
consensus rules are often described by their potential to create either
a hard or soft fork. For example, "increasing the block size above 1 MB
requires a hard fork." In this example, an actual block chain fork is
not required---but it is a possible outcome.
**Resources:** [BIP16][], [BIP30][], and [BIP34][] were implemented as
changes which might have lead to soft forks. [BIP50][] describes both an
accidental hard fork, resolved by temporary downgrading the capabilities
of upgraded nodes, and an intentional hard fork when the temporary
downgrade was removed. A document from Gavin Andresen outlines [how
future rule changes may be
implemented](https://gist.github.com/gavinandresen/2355445).
{% endautocrossref %}
#### Detecting Forks
{% autocrossref %}
Non-upgraded nodes may use and distribute incorrect information during
both types of forks, creating several situations which could lead to
financial loss. In particular, non-upgraded nodes may relay and accept
transactions that are considered invalid by upgraded nodes and so will
never become part of the universally-recognized best block chain.
Non-upgraded nodes may also refuse to relay blocks or transactions which
have already been added to the best block chain, or soon will be, and so
provide incomplete information.
<!-- paragraph below based on src/main.cpp CheckForkWarningConditions() -->
Bitcoin Core includes code that detects a hard fork by looking at block
chain proof of work. If a node receives block chain headers
demonstrating six blocks more proof of work than the best chain this
node considers valid, the node reports an error in the `getinfo` RPC
results and runs the `-alertnotify` command if set.
Full nodes can also check block and transaction version numbers. If the
block or transaction version numbers seen in several recent blocks are
higher than the version numbers the node uses, it can assume it doesn't
use the current consensus rules. Future versions of Bitcoin Core
(>0.9.3) will likely report this situation through the `getinfo` RPC and
`-alertnotify` command if set.
In either case, data should not be relied upon if it comes from a node
that apparently isn't using the current consensus rules.
SPV clients which connect to full nodes can detect a likely hard fork by
connecting to several full nodes and ensuring that they're all on the
same chain with the same block height, plus or minus several blocks to
account for transmission delays and stale blocks. If there's a
divergence, the client can disconnect from nodes with weaker chains.
SPV clients should also monitor for block and transaction version number
increases to ensure they process received transactions and create new
transactions using the current consensus rules.
{% endautocrossref %}

View file

@ -488,7 +488,8 @@ estimate the amount of time until they're added to a block.
Another example could be to detect a fork when multiple peers report differing Another example could be to detect a fork when multiple peers report differing
block header hashes at the same block height. Your program can go into a safe mode if the block header hashes at the same block height. Your program can go into a safe mode if the
fork extends for more than two blocks, indicating a possible problem with the fork extends for more than two blocks, indicating a possible problem with the
block chain. block chain. For more details, see the [Detecting Forks
subsection][section detecting forks].
Another good source of double-spend protection can be human intelligence. For Another good source of double-spend protection can be human intelligence. For
example, fraudsters may act differently from legitimate customers, letting example, fraudsters may act differently from legitimate customers, letting

View file

@ -0,0 +1,92 @@
### Hash Byte Order
{% autocrossref %}
Bitcoin Core RPCs accept and return hashes in the reverse of their
normal byte order. For example, the Unix `sha256sum` command would display the
SHA256(SHA256()) hash of Mainnet block 300,000's header as the
following string:
5472ac8b1187bfcf91d6d218bbda1eb2405d7c55f1f8cc820000000000000000
The string above is also how the hash appears in the
previous-header-hash part of block 300,001's header:
<pre>02000000<b>5472ac8b1187bfcf91d6d218bbda1eb2405d7c55f1f8cc82000\
0000000000000</b>ab0aaa377ca3f49b1545e2ae6b0667a08f42e72d8c24ae\
237140e28f14f3bb7c6bcc6d536c890019edd83ccf</pre>
However Bitcoin RPCs use the reverse byte order for hashes, so if you
want to get information about block 300,000 using the `getblock` RPC,
you need to reverse the byte order:
> bitcoin-cli getblock \
000000000000000082ccf8f1557c5d40b21edabb18d2d691cfbf87118bac7254
(Note: hex representation uses two characters to display each byte of
data, which is why the reversed string looks somewhat mangled.)
The rational for the reversal is unknown, but it likely stems from
Bitcoin's use of hash digests (which are byte arrays in C++) as integers
for the purpose of determining whether the hash is below the network
target. Whatever the reason for reversing header hashes, the reversal
also extends to other hashes used in RPCs, such as TXIDs and merkle
roots.
Off-site documentation such as the Bitcoin Wiki tends to use the terms
big endian and little endian as shown in the table below, but they
aren't always consistent. Worse, these two different ways of
representing a hash digest can confuse anyone who looks at the Bitcoin
Core source code and finds a so-called "big endian" value being stored
in a little-endian data type.
As header hashes and TXIDs are widely used as global identifiers in
other Bitcoin software, this reversal of hashes has become the standard
way to refer to certain objects. The table below should make clear where
each byte order is used.
<div style="text-align: left;" markdown="1">
|---------------+---------------------|-----------------|
| Data | Internal Byte Order ("Big Endian") | RPC Byte Order ("Little Endian") |
|---------------|---------------------|-----------------|
| Example: SHA256(SHA256(0x00)) | Hash: 1406...539a | Hash: 9a53...0614 |
|---------------|---------------------|-----------------|
| Header Hashes: SHA256(SHA256(block header)) | Used when constructing block headers | Used by RPCs such as `getblock`; widely used in block explorers |
|---------------|---------------------|-----------------|
| merkle Roots: SHA256(SHA256(TXIDs and merkle rows)) | Used when constructing block headers | Returned by RPCs such as `getblock` |
|---------------|---------------------|-----------------|
| TXIDs: SHA256(SHA256(transaction)) | Used in transaction inputs | Used by RPCs such as `gettransaction` and transaction data parts of `getblock`; widely used in wallet programs |
|---------------|---------------------|-----------------|
| P2PKH Hashes: RIPEMD160(SHA256(pubkey)) | Used in both addresses and pubkey scripts | **N/A:** RPCs use addresses which use internal byte order |
|---------------|---------------------|-----------------|
| P2SH Hashes: RIPEMD160(SHA256(redeem script)) | Used in both addresses and pubkey scripts | **N/A:** RPCs use addresses which use internal byte order |
|---------------|---------------------|-----------------|
</div>
Note: RPCs which return raw results, such as `getrawtransaction` or the
raw mode of `getblock`, always display hashes as they appear in blocks
(internal byte order).
The code below may help you check byte order by generating hashes
from raw hex.
{% endautocrossref %}
{% highlight python %}
#!/usr/bin/env python
from sys import byteorder
from hashlib import sha256
## You can put in $data an 80-byte block header to get its header hash,
## or a raw transaction to get its txid
data = "00".decode("hex")
hash = sha256(sha256(data).digest()).digest()
print "Warning: this code only tested on a little-endian x86_64 arch"
print
print "System byte order:", byteorder
print "Internal-Byte-Order Hash: ", hash.encode('hex_codec')
print "RPC-Byte-Order Hash: ", hash[::-1].encode('hex_codec')
{% endhighlight %}

View file

@ -1542,8 +1542,7 @@ An array of *transactions* in [transaction object format][]{:#term-transaction-o
{% autocrossref %} {% autocrossref %}
Each object in the array contains the Each object in the array contains the
rawtransaction *data* in hex and the *hash* of the data in little-endian rawtransaction *data* in hex and the *hash* of the data in RPC byte order.
hex.
{% endautocrossref %} {% endautocrossref %}

View file

@ -89,7 +89,7 @@ bytes commonly used by Bitcoin are:
2. Create a copy of the version and hash; then hash that twice with SHA256: `SHA256(SHA256(version . hash))` 2. Create a copy of the version and hash; then hash that twice with SHA256: `SHA256(SHA256(version . hash))`
3. Extract the four most significant bytes from the double-hashed copy. 3. Extract the first four bytes from the double-hashed copy.
These are used as a checksum to ensure the base hash gets transmitted These are used as a checksum to ensure the base hash gets transmitted
correctly. correctly.
@ -138,6 +138,10 @@ Bitcoin transactions are broadcast between peers and stored in the
block chain in a serialized byte format, called [raw format][]{:#term-raw-format}{:.term}. Bitcoin Core block chain in a serialized byte format, called [raw format][]{:#term-raw-format}{:.term}. Bitcoin Core
and many other tools print and accept raw transactions encoded as hex. and many other tools print and accept raw transactions encoded as hex.
The binary form of a raw transaction is SHA256(SHA256()) hashed to create
its TXID. Bitcoin Core RPCs use a reversed byte order for hashes; see the [subsection about hash byte
order][section hash byte order] for details.
A sample raw transaction is the first non-coinbase transaction, made in A sample raw transaction is the first non-coinbase transaction, made in
[block 170][block170]. To get the transaction, use the `getrawtransaction` RPC with [block 170][block170]. To get the transaction, use the `getrawtransaction` RPC with
that transaction's txid (provided below): that transaction's txid (provided below):
@ -145,7 +149,7 @@ that transaction's txid (provided below):
{% endautocrossref %} {% endautocrossref %}
~~~ ~~~
> getrawtransaction \ > bitcoin-cli getrawtransaction \
f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16 f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16
0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423e\ 0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423e\

View file

@ -1,5 +1,4 @@
[51 percent attack]: /en/developer-guide#term-51-attack "The ability of someone controlling a majority of hashing power to revise transactions history and prevent new transactions from confirming" [51 percent attack]: /en/developer-guide#term-51-attack "The ability of someone controlling a majority of hashing power to revise transactions history and prevent new transactions from confirming"
[accidental fork]: /en/developer-guide#term-accidental-fork "When two or more blocks have the same block height, forking the block chain. Happens occasionally by accident"
[addresses]: /en/developer-guide#term-address "A 20-byte hash formatted as a P2PKH or P2SH Bitcoin Address" [addresses]: /en/developer-guide#term-address "A 20-byte hash formatted as a P2PKH or P2SH Bitcoin Address"
[address]: /en/developer-guide#term-address "A 20-byte hash formatted as a P2PKH or P2SH Bitcoin Address" [address]: /en/developer-guide#term-address "A 20-byte hash formatted as a P2PKH or P2SH Bitcoin Address"
[base58Check]: /en/developer-reference#term-base58check "The method used in Bitcoin for converting 160-bit hashes into Bitcoin addresses" [base58Check]: /en/developer-reference#term-base58check "The method used in Bitcoin for converting 160-bit hashes into Bitcoin addresses"
@ -30,6 +29,8 @@
[confirmed transactions]: /en/developer-guide#term-confirmation "Transactions included in a block currently on the block chain" [confirmed transactions]: /en/developer-guide#term-confirmation "Transactions included in a block currently on the block chain"
[confirmation]: /en/developer-guide#term-confirmation "The number of blocks which would need to be modified to remove or modify a transaction" [confirmation]: /en/developer-guide#term-confirmation "The number of blocks which would need to be modified to remove or modify a transaction"
[confirmations]: /en/developer-guide#term-confirmation "The number of blocks which would need to be modified to remove or modify a transaction" [confirmations]: /en/developer-guide#term-confirmation "The number of blocks which would need to be modified to remove or modify a transaction"
[consensus]: /en/developer-guide#term-consensus "When several nodes (usually most nodes on the network) all have the same blocks in their locally-validated block chain."
[consensus rules]: /en/developer-guide#term-consensus-rules "The block validation rules that full nodes follow to stay in consensus with other nodes."
[denomination]: /en/developer-guide#term-denomination "bitcoins (BTC), bitcents (cBTC), millibits (mBTC), microbits (uBTC), or satoshis" [denomination]: /en/developer-guide#term-denomination "bitcoins (BTC), bitcents (cBTC), millibits (mBTC), microbits (uBTC), or satoshis"
[difficulty]: /en/developer-guide#term-difficulty "A number corresponding to the target threshold which indicates how difficult it will be to find the next block" [difficulty]: /en/developer-guide#term-difficulty "A number corresponding to the target threshold which indicates how difficult it will be to find the next block"
[double spend]: /en/developer-guide#term-double-spend "Attempting to spend the same satoshis which were spent in a previous transaction" [double spend]: /en/developer-guide#term-double-spend "Attempting to spend the same satoshis which were spent in a previous transaction"
@ -38,7 +39,9 @@
[extended public key]: /en/developer-guide#term-extended-public-key "A public key extended with the chain code so that it can derive child public keys" [extended public key]: /en/developer-guide#term-extended-public-key "A public key extended with the chain code so that it can derive child public keys"
[escrow contract]: /en/developer-guide#term-escrow-contract "A contract in which the spender and receiver store satoshis in a multisig output until both parties agree to release the satoshis" [escrow contract]: /en/developer-guide#term-escrow-contract "A contract in which the spender and receiver store satoshis in a multisig output until both parties agree to release the satoshis"
[fiat]: /en/developer-guide#term-fiat "National currencies such as the dollar or euro" [fiat]: /en/developer-guide#term-fiat "National currencies such as the dollar or euro"
[fork]: /en/developer-guide#term-fork "When two or more blocks have the same block height, forking the block chain."
[genesis block]: /en/developer-guide#term-genesis-block "The first block created; also called block 0" [genesis block]: /en/developer-guide#term-genesis-block "The first block created; also called block 0"
[hard fork]: /en/developer-guide#term-hard-fork "A permanent divergence in the the block chain, commonly occurs when non-upgraded nodes can't validate blocks created by upgraded nodes following newer consensus rules."
[hardened extended private key]: /en/developer-guide#term-hardened-extended-private-key "A private key whose corresponding public key cannot derive child keys" [hardened extended private key]: /en/developer-guide#term-hardened-extended-private-key "A private key whose corresponding public key cannot derive child keys"
[HD protocol]: /en/developer-guide#term-hd-protocol "The Hierarchical Deterministic (HD) key creation and transfer protocol" [HD protocol]: /en/developer-guide#term-hd-protocol "The Hierarchical Deterministic (HD) key creation and transfer protocol"
[header nonce]: /en/developer-reference#term-header-nonce "Four bytes of arbitrary data in a block header used to let miners create headers with different hashes for proof of work" [header nonce]: /en/developer-reference#term-header-nonce "Four bytes of arbitrary data in a block header used to let miners create headers with different hashes for proof of work"
@ -46,6 +49,7 @@
[input]: /en/developer-guide#term-input "The input to a transaction linking to the output of a previous transaction which permits spending of satoshis" [input]: /en/developer-guide#term-input "The input to a transaction linking to the output of a previous transaction which permits spending of satoshis"
[inputs]: /en/developer-guide#term-input "The input to a transaction linking to the output of a previous transaction which permits spending of satoshis" [inputs]: /en/developer-guide#term-input "The input to a transaction linking to the output of a previous transaction which permits spending of satoshis"
[intermediate certificate]: /en/developer-examples#term-intermediate-certificate "A intermediate certificate authority certificate which helps connect a leaf (receiver) certificate to a root certificate authority" [intermediate certificate]: /en/developer-examples#term-intermediate-certificate "A intermediate certificate authority certificate which helps connect a leaf (receiver) certificate to a root certificate authority"
[internal byte order]: /en/developer-reference#hash-byte-order "The standard order in which hash digests are displayed as strings---the same format used in blocks"
[key index]: /en/developer-guide#term-key-index "An index number used in the HD wallet formula to generate child keys from a parent key" [key index]: /en/developer-guide#term-key-index "An index number used in the HD wallet formula to generate child keys from a parent key"
[key pair]: /en/developer-guide#term-key-pair "A private key and its derived public key" [key pair]: /en/developer-guide#term-key-pair "A private key and its derived public key"
[label]: /en/developer-guide#term-label "The label parameter of a bitcoin: URI which provides the spender with the receiver's name (unauthenticated)" [label]: /en/developer-guide#term-label "The label parameter of a bitcoin: URI which provides the spender with the receiver's name (unauthenticated)"
@ -118,6 +122,7 @@
[regression test mode]: /en/developer-examples#regtest-mode "A local testing environment in which developers can control blocks" [regression test mode]: /en/developer-examples#regtest-mode "A local testing environment in which developers can control blocks"
[root certificate]: /en/developer-examples#term-root-certificate "A certificate belonging to a certificate authority (CA)" [root certificate]: /en/developer-examples#term-root-certificate "A certificate belonging to a certificate authority (CA)"
[root seed]: /en/developer-guide#term-root-seed "A potentially-short value used as a seed to generate a master private key and master chain code for an HD wallet" [root seed]: /en/developer-guide#term-root-seed "A potentially-short value used as a seed to generate a master private key and master chain code for an HD wallet"
[RPC byte order]: /en/developer-reference#hash-byte-order "A hash digest displayed with the byte order reversed; used in Bitcoin Core RPCs and other software."
[satoshi]: /en/developer-guide#term-satoshi "The smallest unit of Bitcoin value; 0.00000001 bitcoins. Also used generically for any value of bitcoins" [satoshi]: /en/developer-guide#term-satoshi "The smallest unit of Bitcoin value; 0.00000001 bitcoins. Also used generically for any value of bitcoins"
[satoshis]: /en/developer-guide#term-satoshi "The smallest unit of Bitcoin value; 0.00000001 bitcoins. Also used generically for any value of bitcoins" [satoshis]: /en/developer-guide#term-satoshi "The smallest unit of Bitcoin value; 0.00000001 bitcoins. Also used generically for any value of bitcoins"
[sequence number]: /en/developer-guide#term-sequence-number "A number intended to allow time locked transactions to be updated before being finalized; not currently used except to disable locktime in a transaction" [sequence number]: /en/developer-guide#term-sequence-number "A number intended to allow time locked transactions to be updated before being finalized; not currently used except to disable locktime in a transaction"
@ -132,6 +137,7 @@
[signature]: /en/developer-guide#term-signature "The result of combining a private key and some data in an ECDSA signature operation which allows anyone with the corresponding public key to verify the signature" [signature]: /en/developer-guide#term-signature "The result of combining a private key and some data in an ECDSA signature operation which allows anyone with the corresponding public key to verify the signature"
[signature hash]: /en/developer-guide#term-signature-hash "A byte appended onto signatures generated in Bitcoin which allows the signer to specify what data was signed, allowing modification of the unsigned data" [signature hash]: /en/developer-guide#term-signature-hash "A byte appended onto signatures generated in Bitcoin which allows the signer to specify what data was signed, allowing modification of the unsigned data"
[signature script]: /en/developer-guide#term-signature-script "Data generated by a spender which is almost always used as variables to satisfy a pubkey script" [signature script]: /en/developer-guide#term-signature-script "Data generated by a spender which is almost always used as variables to satisfy a pubkey script"
[soft fork]: /en/developer-guide#term-soft-fork "A temporary fork in the block chain which commonly occurs when miners using non-upgraded nodes violate a new consensus rule their nodes don't know about."
[spv]: /en/developer-guide#simplified-payment-verification-spv "A method for verifying particular transactions were included in blocks without downloading the entire contents of the block chain" [spv]: /en/developer-guide#simplified-payment-verification-spv "A method for verifying particular transactions were included in blocks without downloading the entire contents of the block chain"
[ssl signature]: /en/developer-examples#term-ssl-signature "Signatures created and recognized by major SSL implementations such as OpenSSL" [ssl signature]: /en/developer-examples#term-ssl-signature "Signatures created and recognized by major SSL implementations such as OpenSSL"
[stack]: /en/developer-guide#term-stack "An evaluation stack used in Bitcoin's script language" [stack]: /en/developer-guide#term-stack "An evaluation stack used in Bitcoin's script language"
@ -160,9 +166,13 @@
[X509Certificates]: /en/developer-examples#term-x509certificates [X509Certificates]: /en/developer-examples#term-x509certificates
[BFGMiner]: https://github.com/luke-jr/bfgminer [BFGMiner]: https://github.com/luke-jr/bfgminer
[BIP16]: https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki
[BIP21]: https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki [BIP21]: https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki
[BIP30]: https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki
[BIP32]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki [BIP32]: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
[BIP34]: https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki
[BIP39]: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki [BIP39]: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
[BIP50]: https://github.com/bitcoin/bips/blob/master/bip-0050.mediawiki
[BIP70]: https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki [BIP70]: https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki
[BIP71]: https://github.com/bitcoin/bips/blob/master/bip-0071.mediawiki [BIP71]: https://github.com/bitcoin/bips/blob/master/bip-0071.mediawiki
[BIP72]: https://github.com/bitcoin/bips/blob/master/bip-0072.mediawiki [BIP72]: https://github.com/bitcoin/bips/blob/master/bip-0072.mediawiki
@ -283,7 +293,9 @@
[RPCs]: /en/developer-reference#remote-procedure-calls-rpcs [RPCs]: /en/developer-reference#remote-procedure-calls-rpcs
<!-- [secp256k1]: http://www.secg.org/index.php?action=secg,docs_secg --> <!-- [secp256k1]: http://www.secg.org/index.php?action=secg,docs_secg -->
[secp256k1]: http://perso.univ-rennes1.fr/sylvain.duquesne/master/standards/sec2_final.pdf [secp256k1]: http://perso.univ-rennes1.fr/sylvain.duquesne/master/standards/sec2_final.pdf
[section hash byte order]: /en/developer-reference#hash-byte-order
[section verifying payment]: /en/developer-guide#verifying-payment [section verifying payment]: /en/developer-guide#verifying-payment
[section detecting forks]: /en/developer-guide#detecting-forks
[bitcoin URI subsection]: /en/developer-guide#bitcoin-uri [bitcoin URI subsection]: /en/developer-guide#bitcoin-uri
[SHA256]: https://en.wikipedia.org/wiki/SHA-2 [SHA256]: https://en.wikipedia.org/wiki/SHA-2
[Stratum mining protocol]: http://mining.bitcoin.cz/stratum-mining [Stratum mining protocol]: http://mining.bitcoin.cz/stratum-mining

View file

@ -37,6 +37,8 @@ title: "Developer Reference - Bitcoin"
-- * https://en.bitcoin.it/wiki/API_reference_(JSON-RPC) -- * https://en.bitcoin.it/wiki/API_reference_(JSON-RPC)
--> -->
{% include ref_core_rpc_intro.md %}
### Remote Procedure Calls (RPCs) ### Remote Procedure Calls (RPCs)
**Warning:** the block chain and memory pool can include arbitrary data **Warning:** the block chain and memory pool can include arbitrary data

49
img/dev/en-hard-fork.dot Normal file
View file

@ -0,0 +1,49 @@
digraph {
size=6.25;
rankdir=LR
//splines = ortho;
ranksep = 0.2;
nodesep = 0.1;
edge [ penwidth = 1.75, fontname="Sans" ]
node [ penwidth = 1.75, shape = "box", fontname="Sans", label = "", width=0.3, height=0.3 ]
graph [ penwidth = 1.75, fontname="Sans" ]
invis1 [ shape = "none", label = "Blocks\nFrom\nUpgraded\nNodes" ]
invis0 [ shape = "none", label = "Blocks\nFrom Non-\nUpgraded\nNodes" ];
subgraph cluster_honest {
block0 [ label = "Follows\nOld\nRules" ];
block1 [ label = "Follows\nOld\nRules" ];
block2_1 [ label = "Follows\nOld\nRules" ];
block3_1 [ label = "Follows\nOld\nRules" ];
//block2_1 -> block4 [ style = "invis", minlen = 2 ];
style = "invis";
}
subgraph cluster_attack {
block2 [ label = "Follows\nNew\nRules" ];
block3 [ label = "Follows\nNew\nRules" ];
block4 [ label = "Follows\nNew\nRules" ];
block5 [ label = "Follows\nNew\nRules" ];
style = "invis"
}
invis0 -> block0 [ minlen = 2, style = "dashed" ];
block2_1 -> block3_1;
block0 -> block1 -> block2 -> block3 -> block4 -> block5;
block1 -> block2_1
label = "A Hard Fork: Non-Upgraded Nodes Reject The New Rules, Diverging The Chain"
}

BIN
img/dev/en-hard-fork.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

128
img/dev/en-hard-fork.svg Normal file
View file

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.26.3 (20100126.1600)
-->
<!-- Title: _anonymous_0 Pages: 1 -->
<svg width="450pt" height="147pt"
viewBox="0.00 0.00 450.00 146.89" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph1" class="graph" transform="scale(0.716561 0.716561) rotate(0) translate(4 201)">
<title>_anonymous_0</title>
<polygon fill="white" stroke="white" points="-4,5 -4,-201 625,-201 625,5 -4,5"/>
<text text-anchor="middle" x="310" y="-8.4" font-family="Sans" font-size="14.00">A Hard Fork: &#160;Non&#45;Upgraded Nodes Reject The New Rules, Diverging The Chain</text>
<g id="graph2" class="cluster"><title>cluster_honest</title>
</g>
<g id="graph3" class="cluster"><title>cluster_attack</title>
</g>
<!-- invis1 -->
<g id="node1" class="node"><title>invis1</title>
<text text-anchor="middle" x="45" y="-90.4" font-family="Sans" font-size="14.00">Blocks</text>
<text text-anchor="middle" x="45" y="-73.4" font-family="Sans" font-size="14.00">From</text>
<text text-anchor="middle" x="45" y="-56.4" font-family="Sans" font-size="14.00">Upgraded</text>
<text text-anchor="middle" x="45" y="-39.4" font-family="Sans" font-size="14.00">Nodes</text>
</g>
<!-- invis0 -->
<g id="node2" class="node"><title>invis0</title>
<text text-anchor="middle" x="45" y="-173.4" font-family="Sans" font-size="14.00">Blocks</text>
<text text-anchor="middle" x="45" y="-156.4" font-family="Sans" font-size="14.00">From Non&#45;</text>
<text text-anchor="middle" x="45" y="-139.4" font-family="Sans" font-size="14.00">Upgraded</text>
<text text-anchor="middle" x="45" y="-122.4" font-family="Sans" font-size="14.00">Nodes</text>
</g>
<!-- block0 -->
<g id="node4" class="node"><title>block0</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="190,-181.5 122,-181.5 122,-122.5 190,-122.5 190,-181.5"/>
<text text-anchor="middle" x="156" y="-164.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="156" y="-147.9" font-family="Sans" font-size="14.00">Old</text>
<text text-anchor="middle" x="156" y="-130.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- invis0&#45;&gt;block0 -->
<g id="edge4" class="edge"><title>invis0&#45;&gt;block0</title>
<path fill="none" stroke="black" stroke-width="1.75" stroke-dasharray="5,2" d="M89.5084,-152C96.8055,-152 104.367,-152 111.66,-152"/>
<polygon fill="black" stroke="black" points="111.736,-155.5 121.736,-152 111.736,-148.5 111.736,-155.5"/>
</g>
<!-- block1 -->
<g id="node5" class="node"><title>block1</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="272,-181.5 204,-181.5 204,-122.5 272,-122.5 272,-181.5"/>
<text text-anchor="middle" x="238" y="-164.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="238" y="-147.9" font-family="Sans" font-size="14.00">Old</text>
<text text-anchor="middle" x="238" y="-130.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- block0&#45;&gt;block1 -->
<g id="edge8" class="edge"><title>block0&#45;&gt;block1</title>
<path fill="none" stroke="black" stroke-width="1.75" d="M190.3,-152C191.419,-152 192.545,-152 193.675,-152"/>
<polygon fill="black" stroke="black" points="193.837,-155.5 203.837,-152 193.837,-148.5 193.837,-155.5"/>
</g>
<!-- block2_1 -->
<g id="node6" class="node"><title>block2_1</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="356,-181.5 288,-181.5 288,-122.5 356,-122.5 356,-181.5"/>
<text text-anchor="middle" x="322" y="-164.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="322" y="-147.9" font-family="Sans" font-size="14.00">Old</text>
<text text-anchor="middle" x="322" y="-130.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- block1&#45;&gt;block2_1 -->
<g id="edge14" class="edge"><title>block1&#45;&gt;block2_1</title>
<path fill="none" stroke="black" stroke-width="1.75" d="M272.166,-152C273.946,-152 275.745,-152 277.551,-152"/>
<polygon fill="black" stroke="black" points="277.864,-155.5 287.864,-152 277.864,-148.5 277.864,-155.5"/>
</g>
<!-- block2 -->
<g id="node9" class="node"><title>block2</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="356,-99.5 288,-99.5 288,-40.5 356,-40.5 356,-99.5"/>
<text text-anchor="middle" x="322" y="-82.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="322" y="-65.9" font-family="Sans" font-size="14.00">New</text>
<text text-anchor="middle" x="322" y="-48.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- block1&#45;&gt;block2 -->
<g id="edge9" class="edge"><title>block1&#45;&gt;block2</title>
<path fill="none" stroke="black" stroke-width="1.75" d="M267.852,-122.859C273.422,-117.421 279.304,-111.679 285.058,-106.062"/>
<polygon fill="black" stroke="black" points="287.533,-108.537 292.244,-99.0472 282.644,-103.528 287.533,-108.537"/>
</g>
<!-- block3_1 -->
<g id="node7" class="node"><title>block3_1</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="438,-181.5 370,-181.5 370,-122.5 438,-122.5 438,-181.5"/>
<text text-anchor="middle" x="404" y="-164.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="404" y="-147.9" font-family="Sans" font-size="14.00">Old</text>
<text text-anchor="middle" x="404" y="-130.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- block2_1&#45;&gt;block3_1 -->
<g id="edge6" class="edge"><title>block2_1&#45;&gt;block3_1</title>
<path fill="none" stroke="black" stroke-width="1.75" d="M356.3,-152C357.419,-152 358.545,-152 359.675,-152"/>
<polygon fill="black" stroke="black" points="359.837,-155.5 369.837,-152 359.837,-148.5 359.837,-155.5"/>
</g>
<!-- block3 -->
<g id="node10" class="node"><title>block3</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="438,-99.5 370,-99.5 370,-40.5 438,-40.5 438,-99.5"/>
<text text-anchor="middle" x="404" y="-82.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="404" y="-65.9" font-family="Sans" font-size="14.00">New</text>
<text text-anchor="middle" x="404" y="-48.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- block2&#45;&gt;block3 -->
<g id="edge10" class="edge"><title>block2&#45;&gt;block3</title>
<path fill="none" stroke="black" stroke-width="1.75" d="M356.3,-70C357.419,-70 358.545,-70 359.675,-70"/>
<polygon fill="black" stroke="black" points="359.837,-73.5001 369.837,-70 359.837,-66.5001 359.837,-73.5001"/>
</g>
<!-- block4 -->
<g id="node11" class="node"><title>block4</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="522,-99.5 454,-99.5 454,-40.5 522,-40.5 522,-99.5"/>
<text text-anchor="middle" x="488" y="-82.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="488" y="-65.9" font-family="Sans" font-size="14.00">New</text>
<text text-anchor="middle" x="488" y="-48.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- block3&#45;&gt;block4 -->
<g id="edge11" class="edge"><title>block3&#45;&gt;block4</title>
<path fill="none" stroke="black" stroke-width="1.75" d="M438.166,-70C439.946,-70 441.745,-70 443.551,-70"/>
<polygon fill="black" stroke="black" points="443.864,-73.5001 453.864,-70 443.864,-66.5001 443.864,-73.5001"/>
</g>
<!-- block5 -->
<g id="node12" class="node"><title>block5</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="604,-99.5 536,-99.5 536,-40.5 604,-40.5 604,-99.5"/>
<text text-anchor="middle" x="570" y="-82.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="570" y="-65.9" font-family="Sans" font-size="14.00">New</text>
<text text-anchor="middle" x="570" y="-48.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- block4&#45;&gt;block5 -->
<g id="edge12" class="edge"><title>block4&#45;&gt;block5</title>
<path fill="none" stroke="black" stroke-width="1.75" d="M522.3,-70C523.419,-70 524.545,-70 525.675,-70"/>
<polygon fill="black" stroke="black" points="525.837,-73.5001 535.837,-70 525.837,-66.5001 525.837,-73.5001"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

47
img/dev/en-soft-fork.dot Normal file
View file

@ -0,0 +1,47 @@
digraph {
size=6.25;
rankdir=LR
//splines = ortho;
ranksep = 0.2;
nodesep = 0.1;
edge [ penwidth = 1.75, fontname="Sans" ]
node [ penwidth = 1.75, shape = "box", fontname="Sans", label = "", width=0.3, height=0.3 ]
graph [ penwidth = 1.75, fontname="Sans" ]
invis1 [ shape = "none", label = "Blocks\nFrom\nUpgraded\nNodes" ]
invis0 [ shape = "none", label = "Blocks\nFrom Non-\nUpgraded\nNodes" ];
subgraph cluster_honest {
block0 [ label = "Follows\nOld\nRules" ];
block1 [ label = "Follows\nOld\nRules" ];
block2_1 [ label = "Follows Old Rules\nBut Violates\nNew Rules", style = "filled" ];
block2_1 -> block4 [ style = "invis", minlen = 2 ];
block4 [ label = "Follows\nOld\nRules" ];
style = "invis";
}
subgraph cluster_attack {
block2 [ label = "Follows\nOld & New\nRules" ];
block3 [ label = "Follows\nOld & New\nRules" ];
style = "invis"
}
invis0 -> block0 [ minlen = 2, style = "dashed" ];
block0 -> block1 -> block2 -> block3 -> block4;
block1 -> block2_1
label = "A Soft Fork: Blocks Violating New Rules Are Made Stale By The Upgraded Mining Majority"
}

BIN
img/dev/en-soft-fork.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

105
img/dev/en-soft-fork.svg Normal file
View file

@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.26.3 (20100126.1600)
-->
<!-- Title: _anonymous_0 Pages: 1 -->
<svg width="450pt" height="143pt"
viewBox="0.00 0.00 450.00 143.02" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph1" class="graph" transform="scale(0.697674 0.697674) rotate(0) translate(4 201)">
<title>_anonymous_0</title>
<polygon fill="white" stroke="white" points="-4,5 -4,-201 642,-201 642,5 -4,5"/>
<text text-anchor="middle" x="318.5" y="-8.4" font-family="Sans" font-size="14.00">A Soft Fork: &#160;Blocks Violating New Rules Are Made Stale By The Upgraded Mining Majority</text>
<g id="graph2" class="cluster"><title>cluster_honest</title>
</g>
<g id="graph3" class="cluster"><title>cluster_attack</title>
</g>
<!-- invis1 -->
<g id="node1" class="node"><title>invis1</title>
<text text-anchor="middle" x="48.5" y="-90.4" font-family="Sans" font-size="14.00">Blocks</text>
<text text-anchor="middle" x="48.5" y="-73.4" font-family="Sans" font-size="14.00">From</text>
<text text-anchor="middle" x="48.5" y="-56.4" font-family="Sans" font-size="14.00">Upgraded</text>
<text text-anchor="middle" x="48.5" y="-39.4" font-family="Sans" font-size="14.00">Nodes</text>
</g>
<!-- invis0 -->
<g id="node2" class="node"><title>invis0</title>
<text text-anchor="middle" x="48.5" y="-173.4" font-family="Sans" font-size="14.00">Blocks</text>
<text text-anchor="middle" x="48.5" y="-156.4" font-family="Sans" font-size="14.00">From Non&#45;</text>
<text text-anchor="middle" x="48.5" y="-139.4" font-family="Sans" font-size="14.00">Upgraded</text>
<text text-anchor="middle" x="48.5" y="-122.4" font-family="Sans" font-size="14.00">Nodes</text>
</g>
<!-- block0 -->
<g id="node4" class="node"><title>block0</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="193.5,-181.5 125.5,-181.5 125.5,-122.5 193.5,-122.5 193.5,-181.5"/>
<text text-anchor="middle" x="159.5" y="-164.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="159.5" y="-147.9" font-family="Sans" font-size="14.00">Old</text>
<text text-anchor="middle" x="159.5" y="-130.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- invis0&#45;&gt;block0 -->
<g id="edge6" class="edge"><title>invis0&#45;&gt;block0</title>
<path fill="none" stroke="black" stroke-width="1.75" stroke-dasharray="5,2" d="M93.0084,-152C100.305,-152 107.867,-152 115.16,-152"/>
<polygon fill="black" stroke="black" points="115.236,-155.5 125.236,-152 115.236,-148.5 115.236,-155.5"/>
</g>
<!-- block1 -->
<g id="node5" class="node"><title>block1</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="275.5,-181.5 207.5,-181.5 207.5,-122.5 275.5,-122.5 275.5,-181.5"/>
<text text-anchor="middle" x="241.5" y="-164.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="241.5" y="-147.9" font-family="Sans" font-size="14.00">Old</text>
<text text-anchor="middle" x="241.5" y="-130.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- block0&#45;&gt;block1 -->
<g id="edge8" class="edge"><title>block0&#45;&gt;block1</title>
<path fill="none" stroke="black" stroke-width="1.75" d="M193.8,-152C194.919,-152 196.045,-152 197.175,-152"/>
<polygon fill="black" stroke="black" points="197.337,-155.5 207.337,-152 197.337,-148.5 197.337,-155.5"/>
</g>
<!-- block2_1 -->
<g id="node6" class="node"><title>block2_1</title>
<polygon fill="lightgrey" stroke="black" stroke-width="1.75" points="426.5,-181.5 290.5,-181.5 290.5,-122.5 426.5,-122.5 426.5,-181.5"/>
<text text-anchor="middle" x="358.5" y="-164.9" font-family="Sans" font-size="14.00">Follows Old Rules</text>
<text text-anchor="middle" x="358.5" y="-147.9" font-family="Sans" font-size="14.00">But Violates</text>
<text text-anchor="middle" x="358.5" y="-130.9" font-family="Sans" font-size="14.00">New Rules</text>
</g>
<!-- block1&#45;&gt;block2_1 -->
<g id="edge13" class="edge"><title>block1&#45;&gt;block2_1</title>
<path fill="none" stroke="black" stroke-width="1.75" d="M275.656,-152C276.946,-152 278.255,-152 279.58,-152"/>
<polygon fill="black" stroke="black" points="279.999,-155.5 289.999,-152 279.999,-148.5 279.999,-155.5"/>
</g>
<!-- block2 -->
<g id="node10" class="node"><title>block2</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="403.5,-99.5 313.5,-99.5 313.5,-40.5 403.5,-40.5 403.5,-99.5"/>
<text text-anchor="middle" x="358.5" y="-82.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="358.5" y="-65.9" font-family="Sans" font-size="14.00">Old &amp; New</text>
<text text-anchor="middle" x="358.5" y="-48.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- block1&#45;&gt;block2 -->
<g id="edge9" class="edge"><title>block1&#45;&gt;block2</title>
<path fill="none" stroke="black" stroke-width="1.75" d="M275.523,-124.375C280.165,-120.81 284.911,-117.267 289.5,-114 294.245,-110.622 299.241,-107.197 304.284,-103.827"/>
<polygon fill="black" stroke="black" points="306.358,-106.652 312.781,-98.2264 302.506,-100.808 306.358,-106.652"/>
</g>
<!-- block4 -->
<g id="node8" class="node"><title>block4</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="617.5,-181.5 549.5,-181.5 549.5,-122.5 617.5,-122.5 617.5,-181.5"/>
<text text-anchor="middle" x="583.5" y="-164.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="583.5" y="-147.9" font-family="Sans" font-size="14.00">Old</text>
<text text-anchor="middle" x="583.5" y="-130.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- block2_1&#45;&gt;block4 -->
<!-- block3 -->
<g id="node11" class="node"><title>block3</title>
<polygon fill="none" stroke="black" stroke-width="1.75" points="532.5,-99.5 442.5,-99.5 442.5,-40.5 532.5,-40.5 532.5,-99.5"/>
<text text-anchor="middle" x="487.5" y="-82.9" font-family="Sans" font-size="14.00">Follows</text>
<text text-anchor="middle" x="487.5" y="-65.9" font-family="Sans" font-size="14.00">Old &amp; New</text>
<text text-anchor="middle" x="487.5" y="-48.9" font-family="Sans" font-size="14.00">Rules</text>
</g>
<!-- block2&#45;&gt;block3 -->
<g id="edge10" class="edge"><title>block2&#45;&gt;block3</title>
<path fill="none" stroke="black" stroke-width="1.75" d="M404.344,-70C413.183,-70 422.534,-70 431.651,-70"/>
<polygon fill="black" stroke="black" points="431.804,-73.5001 441.804,-70 431.804,-66.5001 431.804,-73.5001"/>
</g>
<!-- block3&#45;&gt;block4 -->
<g id="edge11" class="edge"><title>block3&#45;&gt;block4</title>
<path fill="none" stroke="black" stroke-width="1.75" d="M523.732,-99.0918C529.712,-104.016 535.812,-109.115 541.5,-114 542.321,-114.705 543.148,-115.419 543.981,-116.141"/>
<polygon fill="black" stroke="black" points="541.724,-118.817 551.549,-122.781 546.34,-113.555 541.724,-118.817"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB