Cardano-db-sync: Odd mismatch between reward table and block table

Created on 2 Nov 2020  ·  7Comments  ·  Source: input-output-hk/cardano-db-sync

This is incredibly similar to #361.

On mainnet:

cexplorer=# select reward.* from pool_hash
              inner join reward on reward.pool_id = pool_hash.id
              where pool_hash.hash_raw = '\x964d8d35d91603e0dcfbc64891ee8ffeba0e503ca96bf627bc8bcb55' ; 
   id   | addr_id |    amount    | epoch_no | pool_id | block_id 
--------+---------+--------------+----------+---------+----------
 452424 |   92628 | 133076705980 |      222 |    1250 |  4832319
 508325 |   92628 | 126562664576 |      223 |    1250 |  4853643
(2 rows)

suggesting these rewards were earned by pool_id == 1250.

However:

cexplorer=# select block.block_no, slot_leader.pool_hash_id
              from block inner join slot_leader on block.slot_leader_id = slot_leader.id
              where pool_hash_id = 1250 ;
 block_no | pool_hash_id 
----------+--------------
(0 rows)

If these turns out to be caused by a similar problem to the one solved in #361, we definitely need a validation to cover this.

Most helpful comment

@erikd what I told you yesterday was incorrect, apologies. I checked both the spec and the implementation today, which agree and work as follows.

The reward accounts in the stake pool certs:

  • do need to be registered
  • do NOT need to be delegated

Moreover, if two pools list a common reward account, the account gets the sum of the rewards.

All 7 comments

This is different from #361. Looking at the addr_id from above:

cexplorer=# select * from delegation where addr_id = 92628 ;
 id | addr_id | cert_index | pool_hash_id | active_epoch_no | tx_id 
----+---------+------------+--------------+-----------------+-------
(0 rows)

That means this addr_id must be the reward address for a pool update which is trivial to confirm:

cexplorer=# select id, hash_id, pledge, margin, fixed_cost, active_epoch_no, reward_addr_id
              from pool_update where reward_addr_id = 92628 ;
  id  | hash_id | pledge | margin | fixed_cost | active_epoch_no | reward_addr_id 
------+---------+--------+--------+------------+-----------------+----------------
 4621 |    1245 |      0 |      1 |  340000000 |             218 |          92628
 4622 |    1246 |      0 |      1 |  340000000 |             218 |          92628
 4623 |    1247 |      0 |      1 |  340000000 |             218 |          92628
 4624 |    1248 |      0 |      1 |  340000000 |             218 |          92628
 4625 |    1249 |      0 |      1 |  340000000 |             218 |          92628
 4626 |    1250 |      0 |      1 |  340000000 |             218 |          92628
 5683 |    1245 |      0 |      1 |  340000000 |             224 |          92628
 5684 |    1246 |      0 |      1 |  340000000 |             224 |          92628
 5685 |    1247 |      0 |      1 |  340000000 |             224 |          92628
(9 rows)

That means this address is the reward address for a number of different pools. This must be the issue.

This is tricky. I had an assumption in my head that a single stake_address could only delegate to a single pool. While that is true, a single stake_address can be used as the reward address for more than one pool.

Its actually more complicated than that. If a stake_address is used as the reward address for two pools, the reward amount will be the sum of the rewards for each pool. Given what I currently have, I am not sure this egg can be unscrambled.

This is not just tricky, its a complete can of worms.

After chatting on IOHK internal Slack with @JaredCorduan I realized db-syncs treatment of on-chain data was not fully correct and that some SPOs may not have set up their pools correctly.

Firstly, if a pool is registered with a stake/reward address that itself has never been registered as a stake address, then according to point 3 ot section 3.3.4 of the Shelley Design Spec:

Should the reward address be unregistered, the stake pool operator will be unable to receive rewards. In that case, any rewards that they would be due are instead sent back to the reserves (but the stake pool members would still get their usual rewards).

Secondly, if two or more pools are registered with the same stake/reward address and two or more pools earn rewards, then only rewards for the first (how is "first" determined?) pool go to the address and all the rest goes to the reserves/treasury. I have not yet found proper documentation on this.

@erikd what I told you yesterday was incorrect, apologies. I checked both the spec and the implementation today, which agree and work as follows.

The reward accounts in the stake pool certs:

  • do need to be registered
  • do NOT need to be delegated

Moreover, if two pools list a common reward account, the account gets the sum of the rewards.

It currently looks like the fix for this is in a lower level library. @JaredCorduan is looking into it.

Not sure what is going on here. Things have changed.

> select * from pool_hash
      where pool_hash.hash_raw = '\x964d8d35d91603e0dcfbc64891ee8ffeba0e503ca96bf627bc8bcb55' ;
  id  |                          hash_raw                          |                           view                           
------+------------------------------------------------------------+----------------------------------------------------------
 4626 | \x964d8d35d91603e0dcfbc64891ee8ffeba0e503ca96bf627bc8bcb55 | pool1jexc6dwezcp7ph8mceyfrm50l6aqu5pu494lvfau309422t9c6z

but:

> select reward.* from pool_hash
      inner join reward on reward.pool_id = pool_hash.id
      where pool_hash.hash_raw = '\x964d8d35d91603e0dcfbc64891ee8ffeba0e503ca96bf627bc8bcb55' ;
 id | addr_id | amount | epoch_no | pool_id | block_id | type 
----+---------+--------+----------+---------+----------+------
(0 rows)

These queries were run against a database running master at commit f7ee30a245131255f816d6952ef6f0b938e61b94

Ah, but the query of the reward table (which returns zero entries) is correct:

> select block.block_no, slot_leader.pool_hash_id
              from block inner join slot_leader on block.slot_leader_id = slot_leader.id
              where pool_hash_id = 4626 ;
 block_no | pool_hash_id 
----------+--------------
(0 rows)

So the odd mismatch is gone and this ticket can be closed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

erikd picture erikd  ·  10Comments

rcmorano picture rcmorano  ·  6Comments

refi93 picture refi93  ·  15Comments

erikd picture erikd  ·  10Comments

rhyslbw picture rhyslbw  ·  4Comments