<p>The block height for a transaction may be recorded in two different places: the txindex, or in the wallet. Both of these have functions that can take a transaction hash and return information about the transaction, including the transaction itself, the block hash it is confirmed in, etc. However these are not always available as they are optional features, nor are they available in all parts of the codebase. It depends on what you are actually trying to do.</p>
<p>Without a txindex or a wallet, it's not possible to get the block height as this data is not recorded anywhere, and generally does not need to be.</p>
<hr />
<p>If you are in the wallet, i.e. have a <code>CWallet</code> available, then you can do something like:</p>
<pre><code>// Assuming wallet is a CWallet&amp; that already exists
// Assuming tx is a CTransactionRef that already exists
const CWalletTx* wtx = wallet.GetWalletTx(tx-&gt;GetHash());
if (wtx &amp;&amp; (auto conf = wtx-&gt;state&lt;TxStateConfirmed&gt;())) {
    uint256 block_hash = conf-&gt;confirmed_block_hash;
    int block_height;
    chain().findBlock(block_hash, FoundBlock().height(block_height));
}
</code></pre>
<p>The height will be placed into <code>block_height</code>.</p>
<hr />
<p>If the txindex is available, you could do something like:</p>
<pre><code>// Assuming tx is a CTranasctionRef that already exists
// Assuming chainman is a CChainMan that already exists
CTransactionRef dummy;
uint256 block_hash;
g_txindex-&gt;FindTx(tx-&gt;GetHash(), block_hash, dummy);
int block_height = chainman.m_blockman.LookupBlockIndex(block_hash)-&gt;nHeight;
</code></pre>
<p>The <code>FindTx</code> function will lookup the transaction in the txindex given by the hash in the first parameter. The block hash will be placed into the second parameter, and the transaction that was found into the third parameter.</p>

CC BY-SA 4.0
2023-10-06T23:42:06.623Z
Thanks, I think I may be able to get a reference to `g_txindex`. How would I determine the block height int once I have `block_hash`? Is there an index I can use to get that value as well?
danosphere
CC BY-SA 4.0
2023-10-06T23:50:14.600Z
Oops, forgot to include that in my answer. Updated it with how you can get the height from the hash.
Ava Chow
CC BY-SA 4.0
2023-10-07T02:26:50.283Z
Excellent, the last piece I need is any tips on how to get a reference to a CChainMan object?
danosphere
CC BY-SA 4.0
2023-10-07T02:38:42.993Z
It depends on where in the code you are. You could grep around wherever you are to see if there's anything nearby that uses a chainman.
Ava Chow
CC BY-SA 4.0
2023-10-13T21:06:16.600Z
I'm in validation.cpp and I have a reference to a CTransaction, CChainMan and CBlockMan. Any suggestions on the best way to get to the block height from that context given the references I currently have? I don't see an easy way to get to `g_txindex` from this file or CWalletTx. I was looking at how rawtransaction.cpp gets the block hash and it uses node::GetTransaction, would you recommend that given this context? Thanks!
danosphere
CC BY-SA 4.0
2023-10-17T18:06:41.287Z
validation.cpp is pretty deep in the internals. You could probably get `g_txindex` by including `src/index/txindex.h`, however that does seem a bit like a layer violation. What exactly are you trying to do?
Ava Chow
CC BY-SA 4.0
2023-10-17T18:34:08.080Z
Thanks again for the help. Yeah I agree that it might be best to avoid `g_txindex` particularly because of what we're trying to do and every node will need to execute this logic and if I understand `g_txindex` it required `txindex=1` which not all nodes will be utilizing thus creating potential fork issues.

We have added a feature to core which utilized a 2 of 2 signature scheme for the early stages of the chain but we're now trying to move to a 7 of 9 scheme. We need to add hard fork logic so that if the tx/block height is <= n 2of2 is used, otherwise 7of9 is used.
danosphere
CC BY-SA 4.0
2023-10-17T18:36:13.590Z
The feature code is well encapsulated in it's own class/file. The class is implemented within validation.cpp primarily in `MemPoolAccept::PreChecks` and `CScriptCheck::operator()()`.
danosphere
CC BY-SA 4.0
2023-10-17T19:18:01.163Z
The CTransactionRefs that you have should have been retrieved from something that has some chain context - either it comes from a block or it's being validated for mempool acceptance. You shouldn't have just a transaction for which you have no other information about it. If the transaction is in a block, then you can pass down references to the block info to get the height, and if it's for the mempool, then you use the current active tip.
Ava Chow
CC BY-SA 4.0
2023-10-18T04:52:06.997Z
I'm able to get to the data I need using `g_chainman`, `g_blockman`, `g_mempool` and `GetTransaction(..)`. I seem to be getting different results based on the `txindex` config. I want to make sure the validation changes will be consistent for all nodes regardless of `txindex` settings. Is it reliable to use these g_* references even in the absence of `txindex` or should I utilize a different type of reference to those classes (like the m_* refs)?
danosphere
CC BY-SA 4.0
2023-10-18T08:05:58.413Z
Here's some reference code where I'm pulling the values using the g_* managers from within `CScriptCheck::operator()()` of validation.cpp - https://gist.github.com/dwasyluk/54d7d51e9ca31343f0864eda5fca47bf. It seems like when `txindex=0`, block_hash is always 000s but when `txindex=1` valid block hashes are returned.

I think this will create a fork between clients that are running with txindex enabled and those that aren't. Is there a manager I can use to lookup the block indexes that isn't dependent on `txindex`? Perhaps `active_chainstate` or one of the m_* managers?
danosphere
CC BY-SA 4.0
2023-10-19T03:53:52.017Z
There's been ongoing work that removes globals like `g_blockman`, so it won't be available in the future. The way that you're retrieving the block hash requires the txindex, so when it is disabled (`txindex=0`), you won't get a block hash as that information is not available. There are no other indexes that can do this lookup for you, but `CScritptCheck` is created and called within contexts that have a block, or from within the mempool, so you can modify `CScriptCheck` to take a `CBlockIndex`.
Ava Chow
CC BY-SA 4.0
2023-10-06T23:21:48.650Z
2023-10-06T23:49:59.043Z
2023-10-06T23:49:59.043Z
Ava Chow
<p>I'm working with the Bitcoin core code. I have a CTransactionRef object and I'm trying to determine what the block height of the block containing the transaction is. What would be the most efficient way to determine the height given the starting point of a CTransactionRef?</p>

<bitcoin-core><transactions><bitcoind><c++>
How to get block height from CTransactionRef object in Bitcoin C++ code?
danosphere
# How to get block height from CTransactionRef object in Bitcoin C++ code?

(Asked by: username_0 on 2023-10-06)

I'm working with the Bitcoin core code. I have a CTransactionRef object and I'm trying to determine what the block height of the block containing the transaction is. What would be the most efficient way to determine the height given the starting point of a CTransactionRef?

**Tags:** bitcoin-core, transactions, bitcoind, c++


---

## 1 answers

### Answer by username_1 on 2023-10-06. Score: 2

The block height for a transaction may be recorded in two different places: the txindex, or in the wallet. Both of these have functions that can take a transaction hash and return information about the transaction, including the transaction itself, the block hash it is confirmed in, etc. However these are not always available as they are optional features, nor are they available in all parts of the codebase. It depends on what you are actually trying to do.

Without a txindex or a wallet, it's not possible to get the block height as this data is not recorded anywhere, and generally does not need to be.

---

If you are in the wallet, i.e. have a `CWallet` available, then you can do something like:

```
// Assuming wallet is a CWallet& that already exists
// Assuming tx is a CTransactionRef that already exists
const CWalletTx* wtx = wallet.GetWalletTx(tx->GetHash());
if (wtx && (auto conf = wtx->state<TxStateConfirmed>())) {
    uint256 block_hash = conf->confirmed_block_hash;
    int block_height;
    chain().findBlock(block_hash, FoundBlock().height(block_height));
}

```

The height will be placed into `block_height`.

---

If the txindex is available, you could do something like:

```
// Assuming tx is a CTranasctionRef that already exists
// Assuming chainman is a CChainMan that already exists
CTransactionRef dummy;
uint256 block_hash;
g_txindex->FindTx(tx->GetHash(), block_hash, dummy);
int block_height = chainman.m_blockman.LookupBlockIndex(block_hash)->nHeight;

```

The `FindTx` function will lookup the transaction in the txindex given by the hash in the first parameter. The block hash will be placed into the second parameter, and the transaction that was found into the third parameter.

> **Comments:**
> **username_0**: Thanks, I think I may be able to get a reference to `g_txindex`. How would I determine the block height int once I have `block_hash`? Is there an index I can use to get that value as well?  
> **username_1**: Oops, forgot to include that in my answer. Updated it with how you can get the height from the hash.  
> **username_0**: Excellent, the last piece I need is any tips on how to get a reference to a CChainMan object?  
> **username_1**: It depends on where in the code you are. You could grep around wherever you are to see if there's anything nearby that uses a chainman.  
> **username_0**: I'm in validation.cpp and I have a reference to a CTransaction, CChainMan and CBlockMan. Any suggestions on the best way to get to the block height from that context given the references I currently have? I don't see an easy way to get to `g_txindex` from this file or CWalletTx. I was looking at how rawtransaction.cpp gets the block hash and it uses node::GetTransaction, would you recommend that given this context? Thanks!  
> **username_1**: validation.cpp is pretty deep in the internals. You could probably get `g_txindex` by including `src/index/txindex.h`, however that does seem a bit like a layer violation. What exactly are you trying to do?  
> **username_0**: Thanks again for the help. Yeah I agree that it might be best to avoid `g_txindex` particularly because of what we're trying to do and every node will need to execute this logic and if I understand `g_txindex` it required `txindex=1` which not all nodes will be utilizing thus creating potential fork issues.  We have added a feature to core which utilized a 2 of 2 signature scheme for the early stages of the chain but we're now trying to move to a 7 of 9 scheme. We need to add hard fork logic so that if the tx/block height is <= n 2of2 is used, otherwise 7of9 is used.  
> **username_0**: The feature code is well encapsulated in it's own class/file. The class is implemented within validation.cpp primarily in `MemPoolAccept::PreChecks` and `CScriptCheck::operator()()`.  
> **username_1**: The CTransactionRefs that you have should have been retrieved from something that has some chain context - either it comes from a block or it's being validated for mempool acceptance. You shouldn't have just a transaction for which you have no other information about it. If the transaction is in a block, then you can pass down references to the block info to get the height, and if it's for the mempool, then you use the current active tip.  
> **username_0**: I'm able to get to the data I need using `g_chainman`, `g_blockman`, `g_mempool` and `GetTransaction(..)`. I seem to be getting different results based on the `txindex` config. I want to make sure the validation changes will be consistent for all nodes regardless of `txindex` settings. Is it reliable to use these g_* references even in the absence of `txindex` or should I utilize a different type of reference to those classes (like the m_* refs)?  
> **username_0**: Here's some reference code where I'm pulling the values using the g_* managers from within `CScriptCheck::operator()()` of validation.cpp - https://gist.github.com/dwasyluk/54d7d51e9ca31343f0864eda5fca47bf. It seems like when `txindex=0`, block_hash is always 000s but when `txindex=1` valid block hashes are returned.  I think this will create a fork between clients that are running with txindex enabled and those that aren't. Is there a manager I can use to lookup the block indexes that isn't dependent on `txindex`? Perhaps `active_chainstate` or one of the m_* managers?  
> **username_1**: There's been ongoing work that removes globals like `g_blockman`, so it won't be available in the future. The way that you're retrieving the block hash requires the txindex, so when it is disabled (`txindex=0`), you won't get a block hash as that information is not available. There are no other indexes that can do this lookup for you, but `CScritptCheck` is created and called within contexts that have a block, or from within the mempool, so you can modify `CScriptCheck` to take a `CBlockIndex`.  

---

