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.
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-sync
s 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:
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.
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:
Moreover, if two pools list a common reward account, the account gets the sum of the rewards.