mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
Check SPV proof inner nodes not to be valid transactions. (#4436)
This commit is contained in:
parent
7797af6ffa
commit
61a9deaa61
1 changed files with 26 additions and 2 deletions
|
@ -20,8 +20,12 @@
|
||||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
from .util import ThreadJob
|
from .util import ThreadJob, bh2u
|
||||||
from .bitcoin import Hash, hash_decode, hash_encode
|
from .bitcoin import Hash, hash_decode, hash_encode
|
||||||
|
from .transaction import Transaction
|
||||||
|
|
||||||
|
|
||||||
|
class InnerNodeOfSpvProofIsValidTx(Exception): pass
|
||||||
|
|
||||||
|
|
||||||
class SPV(ThreadJob):
|
class SPV(ThreadJob):
|
||||||
|
@ -79,7 +83,12 @@ class SPV(ThreadJob):
|
||||||
tx_hash = params[0]
|
tx_hash = params[0]
|
||||||
tx_height = merkle.get('block_height')
|
tx_height = merkle.get('block_height')
|
||||||
pos = merkle.get('pos')
|
pos = merkle.get('pos')
|
||||||
merkle_root = self.hash_merkle_root(merkle['merkle'], tx_hash, pos)
|
try:
|
||||||
|
merkle_root = self.hash_merkle_root(merkle['merkle'], tx_hash, pos)
|
||||||
|
except InnerNodeOfSpvProofIsValidTx:
|
||||||
|
self.print_error("merkle verification failed for {} (inner node looks like tx)"
|
||||||
|
.format(tx_hash))
|
||||||
|
return
|
||||||
header = self.network.blockchain().read_header(tx_height)
|
header = self.network.blockchain().read_header(tx_height)
|
||||||
# FIXME: if verification fails below,
|
# FIXME: if verification fails below,
|
||||||
# we should make a fresh connection to a server to
|
# we should make a fresh connection to a server to
|
||||||
|
@ -112,8 +121,23 @@ class SPV(ThreadJob):
|
||||||
for i in range(len(merkle_s)):
|
for i in range(len(merkle_s)):
|
||||||
item = merkle_s[i]
|
item = merkle_s[i]
|
||||||
h = Hash(hash_decode(item) + h) if ((pos >> i) & 1) else Hash(h + hash_decode(item))
|
h = Hash(hash_decode(item) + h) if ((pos >> i) & 1) else Hash(h + hash_decode(item))
|
||||||
|
cls._raise_if_valid_tx(bh2u(h))
|
||||||
return hash_encode(h)
|
return hash_encode(h)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _raise_if_valid_tx(cls, raw_tx: str):
|
||||||
|
# If an inner node of the merkle proof is also a valid tx, chances are, this is an attack.
|
||||||
|
# https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-June/016105.html
|
||||||
|
# https://lists.linuxfoundation.org/pipermail/bitcoin-dev/attachments/20180609/9f4f5b1f/attachment-0001.pdf
|
||||||
|
# https://bitcoin.stackexchange.com/questions/76121/how-is-the-leaf-node-weakness-in-merkle-trees-exploitable/76122#76122
|
||||||
|
tx = Transaction(raw_tx)
|
||||||
|
try:
|
||||||
|
tx.deserialize()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise InnerNodeOfSpvProofIsValidTx()
|
||||||
|
|
||||||
def undo_verifications(self):
|
def undo_verifications(self):
|
||||||
height = self.blockchain.get_checkpoint()
|
height = self.blockchain.get_checkpoint()
|
||||||
tx_hashes = self.wallet.undo_verifications(self.blockchain, height)
|
tx_hashes = self.wallet.undo_verifications(self.blockchain, height)
|
||||||
|
|
Loading…
Add table
Reference in a new issue