cculianu / Fulcrum

A fast & nimble SPV Server for BCH, BTC, and LTC
Other
323 stars 73 forks source link

Bug: Some Timestamps are wrong #233

Closed andreasgriffin closed 4 months ago

andreasgriffin commented 4 months ago

Some of the timestamps are wrong. Using bdkpython 0.31.0 I query my fulcrum mainnet bitcoin server with

import bdkpython as bdk 
import datetime

network = bdk.Network.BITCOIN
if network == bdk.Network.BITCOIN:
    blockchain_config = bdk.BlockchainConfig.ELECTRUM(
        bdk.ElectrumConfig(
            "my_fulcrum_server:50001", 
            None,
                10,
            10,
            100,
            False
        )
    ) 

blockchain = bdk.Blockchain(blockchain_config)

mnemonic = bdk.Mnemonic.from_string('bacon '*24)
print(mnemonic.as_string())

descriptor = bdk.Descriptor.new_bip84(
            secret_key=bdk.DescriptorSecretKey(network, mnemonic, ''),
             keychain=bdk.KeychainKind.EXTERNAL,
             network=network,
)

change_descriptor = bdk.Descriptor.new_bip84(
            secret_key=bdk.DescriptorSecretKey(network, mnemonic, ''),
             keychain=bdk.KeychainKind.INTERNAL,
             network=network,
)

print(f'xpub {descriptor.as_string()}')

wallet = bdk.Wallet(
             descriptor=descriptor,
             change_descriptor=change_descriptor,
             network=network,
             database_config=bdk.DatabaseConfig.MEMORY(),
         )

wallet.sync(blockchain, None)
balance = wallet.get_balance()
print(f"Wallet balance is: {balance.total}")

for tx in wallet.list_transactions(True):
    print(tx.confirmation_time.height,  datetime.datetime.fromtimestamp(tx.confirmation_time.timestamp).strftime("%Y-%m-%d %H:%M") , tx.txid)

this gives

image

where the marked row has the time: 2023-01-18 06:25

However it should be 2023-09-24 13:57

The row above the marked one has however the correct timestamp. This timestamp bug is likely not in bdkpython, since it disappears if fulcrum is replaced by electrs.

the error is not determinstic, with repeated executions I get different timestamps

image image image and it appears to happen to random transactions image and it appears that the timestamps are mixed up between the different txs image


Fulcrum version: 1.9.7

andreasgriffin commented 4 months ago

If I fetch the transaction directly


import socket
import json

def fetch_transaction(txid):
    host = 'my_fulcrum_server'
    port = 50001

    # Create a socket connection
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)

    # Connect to the server
    s.connect((host, port))

    # Prepare the JSON-RPC payload for fetching the transaction
    payload = {
        "jsonrpc": "2.0",
        "id": 0,
        "method": "blockchain.transaction.get",
        "params": [txid, True],  # True for verbose output
    }
    message = json.dumps(payload) + '\n'

    # Send the request
    s.sendall(message.encode('utf-8'))

    # Receive the response
    response = s.recv(65535).decode('utf-8')  # Increased buffer size to ensure large transactions can be received

    # Close the socket
    s.close()

    # Parse and return the response
    return json.loads(response)

# Example usage
txid = '4cd97314a596200e4c1f89fe9117c7dd8ebd7219d96165e9581803eaa18b4140'  
transaction_info = fetch_transaction(txid)
print(transaction_info)

I get the correct timestamp 1695556676 datetime.datetime(2023, 9, 24, 13, 57, 56).

Also when I fetch the header directly:


def batch_block_header(heights):
    # Replace with the server's host and port you are connecting to
    host = 'my_fulcrum_server'
    port = 50001

    # Create a socket connection
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)

    # Connect to the server
    s.connect((host, port))

    # Prepare the JSON-RPC payload for fetching the transaction
    payload = {
        "jsonrpc": "2.0",
        "id": 0,
        "method": "blockchain.block.header",
        "params": heights
    }
    message = json.dumps(payload) + '\n'

    # Send the request
    s.sendall(message.encode('utf-8'))

    # Receive the response
    response = s.recv(65535).decode('utf-8')  # Increased buffer size to ensure large transactions can be received

    # Close the socket
    s.close()

    # Parse and return the response
    return json.loads(response)

heights = [809142]   

headers = batch_block_header(heights)
print(headers)

It seems to be a bug, that appears only when fetching blockchain.block.header with many headers in a batched way

cculianu commented 4 months ago

I don’t k know what all this is man.

fulcrum doesn’t do anything with timestamps it simply returns blockchain data faithfully

andreasgriffin commented 4 months ago

Yes, the more I find out about this bug, the more I get the impression it is a rust-electrum-client batching problem (that occurs with fulcrum, but not with electrs).

I close this issue and copy the content over to https://github.com/bitcoindevkit/rust-electrum-client/issues/129

cculianu commented 4 months ago

Hmm. Yeah maybe a bug with the rust client. Maybe the rust client is assuming batches come back in the original request order. Fulcrum delivers batching results in a potentially out-of-order way (which is ok as far as the JSON-RPC spec says!).