|
|
|
@ -22,79 +22,10 @@ defmodule Explorer.Chain.Import.Runner.Tokens do |
|
|
|
|
@type holder_count :: non_neg_integer() |
|
|
|
|
@type token_holder_count :: %{contract_address_hash: Hash.Address.t(), count: holder_count()} |
|
|
|
|
|
|
|
|
|
def acquire_contract_address_tokens(repo, contract_address_hashes_and_token_ids) do |
|
|
|
|
initial_query_no_token_id = |
|
|
|
|
from(token in Token, |
|
|
|
|
select: token |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
initial_query_with_token_id = |
|
|
|
|
from(token in Token, |
|
|
|
|
left_join: instance in Token.Instance, |
|
|
|
|
on: token.contract_address_hash == instance.token_contract_address_hash, |
|
|
|
|
select: token |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
{query_no_token_id, query_with_token_id} = |
|
|
|
|
contract_address_hashes_and_token_ids |
|
|
|
|
|> Enum.reduce({initial_query_no_token_id, initial_query_with_token_id}, fn {contract_address_hash, token_id}, |
|
|
|
|
{query_no_token_id, |
|
|
|
|
query_with_token_id} -> |
|
|
|
|
if is_nil(token_id) do |
|
|
|
|
{from( |
|
|
|
|
token in query_no_token_id, |
|
|
|
|
or_where: token.contract_address_hash == ^contract_address_hash |
|
|
|
|
), query_with_token_id} |
|
|
|
|
else |
|
|
|
|
{query_no_token_id, |
|
|
|
|
from( |
|
|
|
|
[token, instance] in query_with_token_id, |
|
|
|
|
or_where: token.contract_address_hash == ^contract_address_hash and instance.token_id == ^token_id |
|
|
|
|
)} |
|
|
|
|
end |
|
|
|
|
end) |
|
|
|
|
|
|
|
|
|
final_query_no_token_id = |
|
|
|
|
if query_no_token_id == initial_query_no_token_id do |
|
|
|
|
nil |
|
|
|
|
else |
|
|
|
|
from( |
|
|
|
|
token in query_no_token_id, |
|
|
|
|
# Enforce Token ShareLocks order (see docs: sharelocks.md) |
|
|
|
|
order_by: [ |
|
|
|
|
token.contract_address_hash |
|
|
|
|
], |
|
|
|
|
lock: "FOR NO KEY UPDATE" |
|
|
|
|
) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
final_query_with_token_id = |
|
|
|
|
if query_with_token_id == initial_query_with_token_id do |
|
|
|
|
nil |
|
|
|
|
else |
|
|
|
|
from( |
|
|
|
|
[token, instance] in query_with_token_id, |
|
|
|
|
# Enforce Token ShareLocks order (see docs: sharelocks.md) |
|
|
|
|
order_by: [ |
|
|
|
|
token.contract_address_hash, |
|
|
|
|
instance.token_id |
|
|
|
|
], |
|
|
|
|
lock: "FOR NO KEY UPDATE OF t0" |
|
|
|
|
) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
tokens_no_token_id = (final_query_no_token_id && repo.all(final_query_no_token_id)) || [] |
|
|
|
|
tokens_with_token_id = (final_query_with_token_id && repo.all(final_query_with_token_id)) || [] |
|
|
|
|
tokens = tokens_no_token_id ++ tokens_with_token_id |
|
|
|
|
|
|
|
|
|
{:ok, tokens} |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def update_holder_counts_with_deltas(repo, token_holder_count_deltas, %{ |
|
|
|
|
timeout: timeout, |
|
|
|
|
timestamps: %{updated_at: updated_at} |
|
|
|
|
}) do |
|
|
|
|
# NOTE that acquire_contract_address_tokens needs to be called before this |
|
|
|
|
{hashes, deltas} = |
|
|
|
|
token_holder_count_deltas |
|
|
|
|
|> Enum.map(fn %{contract_address_hash: contract_address_hash, delta: delta} -> |
|
|
|
@ -103,6 +34,15 @@ defmodule Explorer.Chain.Import.Runner.Tokens do |
|
|
|
|
end) |
|
|
|
|
|> Enum.unzip() |
|
|
|
|
|
|
|
|
|
token_query = |
|
|
|
|
from( |
|
|
|
|
token in Token, |
|
|
|
|
where: token.contract_address_hash in ^hashes, |
|
|
|
|
select: token.contract_address_hash, |
|
|
|
|
order_by: token.contract_address_hash, |
|
|
|
|
lock: "FOR NO KEY UPDATE" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
query = |
|
|
|
|
from( |
|
|
|
|
token in Token, |
|
|
|
@ -113,8 +53,8 @@ defmodule Explorer.Chain.Import.Runner.Tokens do |
|
|
|
|
^deltas |
|
|
|
|
), |
|
|
|
|
on: token.contract_address_hash == deltas.contract_address_hash, |
|
|
|
|
where: token.contract_address_hash in subquery(token_query), |
|
|
|
|
where: not is_nil(token.holder_count), |
|
|
|
|
# ShareLocks order already enforced by `acquire_contract_address_tokens` (see docs: sharelocks.md) |
|
|
|
|
update: [ |
|
|
|
|
set: [ |
|
|
|
|
holder_count: token.holder_count + deltas.delta, |
|
|
|
|