Rust:添加事务时 SQL 查询错误 -“列 'block_index' 不能为空”

问题描述 投票:0回答:1

我正在使用 MySQL 作为数据库,在 Rust 中开发区块链实现。我有两个表:块和交易。交易通过外键(block_index)与块关联。

CREATE TABLE blocks (
    block_index BIGINT NOT NULL PRIMARY KEY,
    previous_hash VARCHAR(255) NOT NULL,
    block_hash VARCHAR(255) NOT NULL,
    validator_signature VARCHAR(255) NOT NULL,
    timestamp DATETIME NOT NULL
);
CREATE TABLE transactions (
    transaction_id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    block_index BIGINT NOT NULL,
    file_hash VARCHAR(255) NOT NULL,
    uploader_id BIGINT,
    uploader_name VARCHAR(255) NOT NULL,
    transaction_checksum VARCHAR(255) NOT NULL,
    timestamp DATETIME NOT NULL,
    FOREIGN KEY (block_index) REFERENCES blocks(block_index)
);
#[derive(Debug, Clone)]
pub struct Transaction {
    pub transaction_id: u64,
    pub block_index: Option<u64>, // Associated block index
    pub file_hash: String,
    pub uploader_id: Option<u64>,
    pub uploader_name: String,
    pub transaction_checksum: String,
    pub timestamp: chrono::DateTime<chrono::Utc>,
}
pub async fn add_transaction(
    &mut self,
    transaction: Transaction,
    pool: &mysql_async::Pool,
) -> Result<(), mysql_async::Error> {
    if transaction.block_index.is_none() {
        return Err(mysql_async::Error::Other(Box::new(std::io::Error::new(
            std::io::ErrorKind::InvalidInput,
            "Transaction must have a valid block_index",
        ))));
    }

    let mut conn = pool.get_conn().await?;
    conn.exec_drop(
        r"INSERT INTO transactions (
            transaction_id, block_index, file_hash, uploader_id, uploader_name, 
     transaction_checksum, timestamp
        ) VALUES (
            :transaction_id, :block_index, :file_hash, :uploader_id, :uploader_name, 
     :transaction_checksum, :timestamp
        )",
        mysql_async::params! {
            "transaction_id" => transaction.transaction_id,
            "block_index" => transaction.block_index.unwrap(),
            "file_hash" => transaction.file_hash,
            "uploader_id" => transaction.uploader_id,
            "uploader_name" => transaction.uploader_name,
            "transaction_checksum" => transaction.transaction_checksum,
            "timestamp" => transaction.timestamp.to_string(),
        },
    ).await?;

    Ok(())
}
#[tokio::test]
async fn test_add_transaction() {
    let database_url = "mysql://root:password@localhost:3306/test_public_blockchain";
    let pool = mysql_async::Pool::new(database_url);

    let mut conn = pool.get_conn().await.unwrap();
    conn.exec_drop("DELETE FROM transactions", ()).await.unwrap();
    conn.exec_drop("DELETE FROM blocks", ()).await.unwrap();

    conn.exec_drop(
        r"INSERT INTO blocks (block_index, previous_hash, block_hash, validator_signature, 
    timestamp)
          VALUES (1, '0', 'genesis_hash', 'validator1', NOW())",
        (),
    ).await.unwrap();

    let transaction = Transaction {
        transaction_id: 1,
        block_index: Some(1),
        file_hash: "test_hash".to_string(),
        uploader_id: Some(1),
        uploader_name: "Test Uploader".to_string(),
        transaction_checksum: "checksum".to_string(),
        timestamp: chrono::Utc::now(),
    };

    let mut blockchain = Blockchain::new(Block::new(0, "0".to_string(), vec![], 
    "validator1".to_string()), vec![]);
    blockchain.add_transaction(transaction.clone(), &pool).await.unwrap();
}

当我运行测试时,出现以下错误:

Server(ServerError { code: 1048, message: "Column 'block_index' cannot be null", state: 
    "23000" })

我在 SQL 查询之前验证了调试日志中的

block_index
值。

我已经确认

block_index = 1
存在于块表中

我手动运行了查询,直接在 MySQL 中执行就可以了

我在插入数据之前添加了

println!
来保证数据,以确保没有任何内容为空或特定的block_index不为空,我已将block_index硬编码为1,但仍然收到它为空的错误,我尝试过禁用外键看看这是否是问题所在,但仍然出现相同的错误

问题:

为什么 block_index 在 Rust 代码中设置为

NULL
时,在查询执行中却显示为
Some(1)
?如何使用 mysql_async crate 在 Rust 中解决这个问题?

mysql rust
1个回答
0
投票

我相信我已经明白了。我添加了创世块,但我错误地尝试将交易添加到创世块,而不是将它们添加到下一个块,下一个块将是创世块之后的第一个块。问题是我的下一个块设置为索引 1 和先前的哈希值 0。一旦我切换到使用块索引 2 和创世块的先前哈希值,我的所有测试都通过了。

© www.soinside.com 2019 - 2024. All rights reserved.