Sergi Delgado-Segura, Surya Bakshi, Cristina Pérez-Solà, James Litton, Andrew Pachulski, Andrew Miller and Bobby Bhattacharjee
TxProbe: Discovering Bitcoin’s Network Topology Using Orphan Transactions
sr_gi
#SFBW19
WHAT DO WE KNOW ABOUT THE TOPOLOGY? WHAT DO WE KNOW ABOUT THE - - PowerPoint PPT Presentation
# SFBW19 TxProbe: Discovering Bitcoins Network Topology Using Orphan Transactions Sergi Delgado-Segura , Surya Bakshi, Cristina Prez-Sol, James Litton, Andrew Pachulski, Andrew Miller and Bobby Bhattacharjee sr_gi WHAT DO WE KNOW ABOUT THE
Sergi Delgado-Segura, Surya Bakshi, Cristina Pérez-Solà, James Litton, Andrew Pachulski, Andrew Miller and Bobby Bhattacharjee
TxProbe: Discovering Bitcoin’s Network Topology Using Orphan Transactions
sr_gi
#SFBW19
Number of nodes and location of them
Number of nodes and location of them
Number of nodes and location of them The edges are hidden by design
We know nothings about how the network really is:
Security by obscurity does not seem the proper way to go
How Bitcoin (Core client) nodes choose their peers?
No pair of nodes in the same /16 (IPv4)
Bitcoin forks based on the Core client follow the same approach
Valid transaction are stored in mempool Transaction in mempool are eventually propagated throughout the node neighborhood
A B
Valid transaction are stored in mempool Transaction in mempool are eventually propagated throughout the node neighborhood
A B i n v ( h ( t x
n
) ) a n n
n c e
Valid transaction are stored in mempool Transaction in mempool are eventually propagated throughout the node neighborhood
A B i n v ( h ( t x
n
) ) get_data(h(txn)) a n n
n c e request
Valid transaction are stored in mempool Transaction in mempool are eventually propagated throughout the node neighborhood
A B i n v ( h ( t x
n
) ) get_data(h(txn)) a n n
n c e request
Wait for tx up to 2 min
Valid transaction are stored in mempool Transaction in mempool are eventually propagated throughout the node neighborhood
A B inv(h(txn)) get_data(h(txn)) tx(txn) announce request deliver
Wait for tx up to 2 min
A transaction is orphan if some of the referenced UTXOs are unknown They can not be validated, so they are stored in a separated data structure known as MapOrphanTransactions (or OrphanPool for short) Transactions in MapOrphanTransactions are NOT forwarded to any node If the same transactions is offered again to the node (inv message), it will not requested back (getaddr)
txB txC txD Orphan transaction
id = 4F3…ED
Source: 4F3…ED
To: Bob
Source: 4F3…ED
To: Alice
txB txB’
. . .
B’s mempool
txn-1 tx0
id = 4F3…ED
Source: 4F3…ED
To: Bob
Source: 4F3…ED
To: Alice
txB txB’
. . .
B’s mempool
txn-1 tx0
id = 4F3…ED
Source: 4F3…ED
To: Bob
Source: 4F3…ED
To: Alice
txB txB’
. . .
B’s mempool
txn-1 tx0 txB
id = 4F3…ED
Source: 4F3…ED
To: Bob
Source: 4F3…ED
To: Alice
txB txB’
. . .
B’s mempool
txn-1 tx0 txB
id = 4F3…ED
Source: 4F3…ED
To: Bob
Source: 4F3…ED
To: Alice
txB txB’
. . .
B’s mempool
txn-1 tx0 txB
Two nodes Three transactions Observation tool (like coinscope)
Two nodes Three transactions Observation tool (like coinscope)
Two nodes Three transactions Observation tool (like coinscope)
txP txM Parent tx Marker tx txF Flood tx
id = 4F3…ED
Two nodes Three transactions Observation tool (like coinscope)
txP txM Parent tx Marker tx txF Flood tx
id = 4F3…ED
US
A’s Mempool B’s Mempool
B’s MapOrphanTransactions
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) ( 1 )
A’s Mempool B’s Mempool
B’s MapOrphanTransactions
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1)
txP txF
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1)
txP txF
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1)
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1)
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1) txM (2)
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1)
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1) txM (2) (2)
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1) txM (2) (2) txM (3)
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1) txM (2) (2)
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1) txM (2) (2) txM (3)
A’s Mempool B’s Mempool
B’s MapOrphanTransactions
A’s Mempool B’s Mempool
B’s MapOrphanTransactions
txP txF (1) ( 1 )
A’s Mempool B’s Mempool
B’s MapOrphanTransactions
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1)
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1) txM (2)
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1)
A’s Mempool B’s Mempool
B’s MapOrphanTransactions txP txF (1) (1) txM (2)
US US
txM (2)
(1) (3) (1)
(1) (2) (1)
US US
txM (2)
(1) (3) (1)
A B inv(h(txM))
US
(1) (2) (1)
US US
txM (2)
(1) (3) (1)
A B inv(h(txM))
US
(1) (2) (1)
US US
txM (2)
(1) (3) (1)
A B inv(h(txM))
US
get_data(h(txM))
(1) (2) (1)
US US
txM (2)
(1) (3) (1)
A B inv(h(txM))
US
edge does not exist
get_data(h(txM))
(1) (2) (1)
US US
txM (2)
(1) (3) (1)
A B inv(h(txM))
US
(1) (2) (1)
US US
txM (2)
(1) (3) (1)
A B inv(h(txM))
US
(1) (2) (1)
US US
txM (2)
(1) (3) (1)
A B inv(h(txM))
US
edge does exist
(1) (2) (1)
Coinscope
US
Coinscope
Long story short, the technique will fail if we add an additional node to the picture
US
Coinscope
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
Coinscope
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
Coinscope
t x P (1) txF (1)
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
Coinscope
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txP
(1)
txF
(1)
Coinscope
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txP
(1)
txF
(1)
Coinscope
t x P (2)
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txP
(1)
txF
(1)
Coinscope
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txP
(1)
txF
(1)
txP
(2)
Coinscope
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txP
(1)
txF
(1)
txP
(2)
Coinscope
t x M (3)
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txP
(1)
txF
(1)
txP
(2)
Coinscope
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txP
(1)
txF
(1)
txP
(2)
Coinscope
txM
(3)
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txP
(1)
txF
(1)
txP
(2)
Coinscope
txM
(3)
t x M (4)
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txP
(1)
txF
(1)
txP
(2)
Coinscope
txM
(3)
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txP
(1)
txF
(1)
txP
(2)
Coinscope
txM
(3)
txM
(4)
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txP
(1)
txF
(1)
txP
(2)
Coinscope
txM
(3)
txM
(4)
txM (5)
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txP
(1)
txF
(1)
txP
(2)
Coinscope
txM
(3)
txM
(4)
Long story short, the technique will fail if we add an additional node to the picture
US
∅ ∅ ∅ ∅
A’s Mempool C’s Mempool B’s Mempool B’s MapOrphanTransactions
txM
(5)
txP
(1)
txF
(1)
txP
(2)
Coinscope
txM
(3)
txM
(4)
Long story short, the technique will fail if we add an additional node to the picture
US
txP
txP
txF
txP
txP
txF
t x P (2)
Coinscope
US
t x P (2)
Coinscope
US
t x P (2)
Coinscope
US
A B
C
t x P (2)
Coinscope
US
A B
C
INV
t x P (2)
Coinscope
US
A B
C
GETDATA INV
t x P (2)
Coinscope
US
A B
C
GETDATA TX INV
t x P (2)
Coinscope
US
A B
C
GETDATA TX INV
t x P (2)
Coinscope
US
A B
C
GETDATA TX INV
t x P (2)
Coinscope
US
A B
C
GETDATA TX INV
t x P (2)
Coinscope
US
A B
C
GETDATA TX INV
Coinscope
US
Coinscope
US
INV(txP) INV(txP) INV(txP)
Coinscope
US
Coinscope
US
Coinscope
US
txP txP txP
GETDATA (txP) GETDATA (txP) GETDATA (txP)
Coinscope
US
txP txP txP
Coinscope
US
txP txP txP
Coinscope
US
txP txP txP
We have a 2-min window where isolation and synchrony are not a problem!
B’s Mempool
txP txP txP
Coinscope
US
C’s Mempool
A’s Mempool B’s Orphanpool
C’s Orphanpool
B’s Mempool
txP txP txP
Coinscope
US
txP
C’s Mempool
A’s Mempool B’s Orphanpool
C’s Orphanpool
B’s Mempool
txP txP txP
Coinscope
US
C’s Mempool
A’s Mempool B’s Orphanpool
C’s Orphanpool
B’s Mempool
txP txP txP
Coinscope
US
C’s Mempool
txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txP txP txP
Coinscope
US
INV(txP )
C’s Mempool
txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txP txP txP
Coinscope
US
C’s Mempool
txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txP txP txP
Coinscope
US
C’s Mempool
txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txP txP txP
Coinscope
US
C’s Mempool
txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txP txP txP
Coinscope
US
txF
C’s Mempool
txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txP txP txP
Coinscope
US
C’s Mempool
txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
C’s Mempool
txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
txF
C’s Mempool
txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
C’s Mempool
txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
C’s Mempool
txF txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
txF
C’s Mempool
txF txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
txF
C’s Mempool
txF txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
txF
C’s Mempool
txF txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
C’s Mempool
txF txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
C’s Mempool
txF txP
A’s Mempool
txP txM
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
C’s Mempool
txF txP
A’s Mempool
txP
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
C’s Mempool
txF txP
A’s Mempool
txP txM
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
C’s Mempool
txF txP
A’s Mempool
txP txM txM
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
C’s Mempool
txF txP
A’s Mempool
txP txM
B’s Orphanpool
C’s Orphanpool
B’s Mempool
txF txP txP txP
Coinscope
US
C’s Mempool
txF txP
A’s Mempool
txP txM
B’s Orphanpool
C’s Orphanpool
txM
B’s Mempool
txF txP txP txP
Coinscope
US
C’s Mempool
txF txP
A’s Mempool
txP txM
B’s Orphanpool
C’s Orphanpool
txM
For every node in the network
precision = 100% recall = 97.40% size degree color Community unfolding
Truly randomised orphan transaction eviction
Fixes INVBLOCKING
Creates block-only relay connections
Bitcoin Core 0.18.0 Bitcoin Core 0.19.0 More info about the fixes: https://bitcoinops.org/en/newsletters/2019/09/18/ h/t David A. Harding (@hrdng)
sr_gi
#SFBW19
Coinscope
US
A’s Mempool
C’s Mempool
B’s Mempool
INV(txF) INV(txP)
Coinscope
US
A’s Mempool
C’s Mempool
B’s Mempool
Coinscope
US
A’s Mempool
C’s Mempool
B’s Mempool
Coinscope
US
txP txF
A’s Mempool
C’s Mempool
B’s Mempool
GETDATA (txF) GETDATA (txP)
Coinscope
US
txP txF
A’s Mempool
C’s Mempool
B’s Mempool
Coinscope
US
txP txF
A’s Mempool
C’s Mempool
B’s Mempool
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txF
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txF
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txF
txF
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txF
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txF
txF
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
INV(txF)
txF
txF
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txF
txF
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txF
txF
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txF
txF
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txP
txF
txF
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txF
txF
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txF
txF
txP
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txP
txF
txF
txP
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txP
txF
txF
txP
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txP
txF
txF
txP
A’s Mempool
C’s Mempool
B’s Mempool
txP txF
Coinscope
US
txF
txF
txP
Coinscope
US
Coinscope
US
A’s Mempool
txP
B’s Mempool
txF
C’s Mempool
txF
A’s Mempool
txP
B’s Mempool
txF
C’s Mempool
txF
txP
txP
txF
while (mapOrphanTransactions.size() > nMaxOrphans) { // Evict a random orphan: uint256 randomhash = rng.rand256(); std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); EraseOrphanTx(it->first); ++nEvicted; }
source: https://github.com/bitcoin/bitcoin/blob/273d025/src/net_processing.cpp#L783-L791
while (mapOrphanTransactions.size() > nMaxOrphans) { // Evict a random orphan: uint256 randomhash = rng.rand256(); std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); EraseOrphanTx(it->first); ++nEvicted; }
source: https://github.com/bitcoin/bitcoin/blob/273d025/src/net_processing.cpp#L783-L791
than, R
UTXO1
UTXO0
sr_gi
#SFBW19