Skip to content

Commit 2f850f0

Browse files
authored
Merge pull request #108 from skalenetwork/develop
Beta release
2 parents b51c1f4 + ccd0b4b commit 2f850f0

37 files changed

Lines changed: 402 additions & 920 deletions

README.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,33 @@ See the [project documentation](https://docs.blockscout.com/) for instructions:
3636
- [ENV variables](https://docs.blockscout.com/setup/env-variables)
3737
- [Configuration options](https://docs.blockscout.com/for-developers/configuration-options)
3838

39-
## Acknowledgements
40-
41-
We would like to thank the EthPrize foundation for their funding support.
39+
# FAIR Network Blockscout Configuration
40+
41+
To deploy Blockscout for FAIR network, an `.env` file should be created based on this template.
42+
43+
## Arguments
44+
### Required
45+
- **HOST** - hostname where the explorer will be accessible _(required)_
46+
- **CHAIN_ID** - chain ID for the FAIR network _(required)_
47+
- **ENDPOINT** - RPC endpoint for blockchain interaction _(required)_
48+
- **WS_ENDPOINT** - WebSocket endpoint for real-time data _(required)_
49+
- **SCHAIN_NAME** - name of the FAIR chain for flexibility purposes _(required)_
50+
- **COMPOSE_PROJECT_NAME** - Docker Compose project name (affects container naming) _(required)_
51+
- **SCHAIN_APP_NAME** - application name shown in the UI _(required)_
52+
- **PROXY_PORT** - HTTP/HTTPS proxy port for external access _(required)_
53+
- **DB_PORT** - database port for main app _(required)_
54+
- **STATS_PORT** - statistics service port _(required)_
55+
- **STATS_DB_PORT** - statistics database port _(required)_
56+
- **WALLET_CONNECT_PROJECT_ID** - WalletConnect project ID for wallet integration _(required)_
57+
### Optional
58+
- **IS_TESTNET** - whether this is a testnet deployment (true/false) _(optional)_
59+
- **BLOCKSCOUT_BACKEND_DOCKER_TAG** - version of blockscout backend container to use _(optional)_
60+
- **BLOCKSCOUT_FRONTEND_DOCKER_TAG** - version of blockscout frontend container to use _(optional)_
61+
- **STATIC_BLOCK_REWARD** - static block reward in wei for emission calculations _(optional)_
62+
- **BURNT_FEE_FRACTION** - fraction of gas fees that are burnt (0.0 to 1.0) _(optional)_
63+
### Required for production
64+
- **DB_PASSWORD** - password for PostgreSQL database _(required for production)_
65+
- **RE_CAPTCHA_SECRET_KEY** - private key used on blockscout server side to securely verify that user interactions are performed by humans _(required for production)_
4266

4367
## Contributing
4468

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.3.0
1+
3.0.0

apps/block_scout_web/lib/block_scout_web/views/api/v2/transaction_view.ex

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,30 @@ defmodule BlockScoutWeb.API.V2.TransactionView do
480480
if Decimal.compare(max_fee_per_gas.value, 0) == :eq do
481481
%Wei{value: Decimal.new(0)}
482482
else
483-
Wei.mult(base_fee_per_gas, transaction.gas_used)
483+
network = System.get_env("NETWORK")
484+
485+
if network == "FAIR" do
486+
# FAIR network logic: use gas_price or max_fee_per_gas multiplied by fraction
487+
fair_burnt_fee_fraction = Application.get_env(:explorer, :fair_burnt_fee_fraction, 0.5)
488+
489+
# Use gas_price if available, otherwise use max_fee_per_gas
490+
effective_gas_price =
491+
if transaction.gas_price do
492+
transaction.gas_price
493+
else
494+
max_fee_per_gas
495+
end
496+
497+
result = effective_gas_price
498+
|> Wei.mult(transaction.gas_used)
499+
|> Wei.mult(Decimal.from_float(fair_burnt_fee_fraction))
500+
501+
# Round to integer wei
502+
%Wei{value: Decimal.round(result.value, 0)}
503+
else
504+
# Original EIP-1559 calculation for non-FAIR networks
505+
Wei.mult(base_fee_per_gas, transaction.gas_used)
506+
end
484507
end
485508
else
486509
nil

apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth.ex

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,71 @@ defmodule EthereumJSONRPC.Geth do
77

88
import EthereumJSONRPC, only: [id_to_params: 1, integer_to_quantity: 1, json_rpc: 2, request: 1]
99

10-
alias EthereumJSONRPC.{FetchedBalance, FetchedCode, PendingTransaction, Utility.CommonHelper}
10+
alias EthereumJSONRPC.{FetchedBalance, FetchedBeneficiaries, FetchedCode, PendingTransaction, Utility.CommonHelper}
1111
alias EthereumJSONRPC.Geth.{Calls, PolygonTracer, Tracer}
1212

1313
@behaviour EthereumJSONRPC.Variant
1414

1515
@doc """
16-
Block reward contract beneficiary fetching is not supported currently for Geth.
17-
18-
To signal to the caller that fetching is not supported, `:ignore` is returned.
16+
Block reward contract beneficiary fetching for FAIR.
1917
"""
2018
@impl EthereumJSONRPC.Variant
21-
def fetch_beneficiaries(_block_range, _json_rpc_named_arguments), do: :ignore
19+
def fetch_beneficiaries(block_numbers, json_rpc_named_arguments) when is_list(block_numbers) do
20+
if is_fair_chain?(json_rpc_named_arguments) do
21+
fetch_fair_beneficiaries(block_numbers, json_rpc_named_arguments)
22+
else
23+
:ignore
24+
end
25+
end
26+
27+
defp is_fair_chain?(_json_rpc_named_arguments) do
28+
# Check if the NETWORK environment variable indicates FAIR network
29+
network = System.get_env("NETWORK", "")
30+
String.upcase(network) == "FAIR"
31+
end
32+
33+
# Fetch beneficiaries for FAIR using block data
34+
defp fetch_fair_beneficiaries(block_numbers, json_rpc_named_arguments) do
35+
requests =
36+
block_numbers
37+
|> Enum.with_index()
38+
|> Enum.map(fn {block_number, id} ->
39+
EthereumJSONRPC.request(%{
40+
id: id,
41+
method: "eth_getBlockByNumber",
42+
params: [EthereumJSONRPC.integer_to_quantity(block_number), false]
43+
})
44+
end)
45+
46+
case EthereumJSONRPC.json_rpc(requests, json_rpc_named_arguments) do
47+
{:ok, responses} ->
48+
params_set =
49+
responses
50+
|> Enum.map(fn %{id: id, result: block} when is_map(block) ->
51+
block_number = Enum.at(block_numbers, id)
52+
miner = Map.get(block, "miner") || Map.get(block, "author")
53+
54+
if miner do
55+
%{
56+
address_hash: miner,
57+
address_type: :validator,
58+
block_hash: Map.get(block, "hash"),
59+
block_number: block_number,
60+
reward: "0x0"
61+
}
62+
else
63+
nil
64+
end
65+
end)
66+
|> Enum.reject(&is_nil/1)
67+
|> MapSet.new()
68+
69+
{:ok, %EthereumJSONRPC.FetchedBeneficiaries{params_set: params_set, errors: []}}
70+
71+
{:error, error} = error_result ->
72+
error_result
73+
end
74+
end
2275

2376
@doc """
2477
Fetches the `t:Explorer.Chain.InternalTransaction.changeset/2` params.

apps/explorer/lib/explorer/chain/block.ex

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -382,16 +382,47 @@ defmodule Explorer.Chain.Block do
382382
"""
383383
@spec burnt_fees(list(), Decimal.t() | nil) :: Decimal.t()
384384
def burnt_fees(transactions, base_fee_per_gas) do
385-
if is_nil(base_fee_per_gas) do
386-
Decimal.new(0)
387-
else
385+
network = System.get_env("NETWORK")
386+
387+
if network == "FAIR" do
388+
fair_burnt_fee_fraction = Application.get_env(:explorer, :fair_burnt_fee_fraction, 0.5)
389+
388390
transactions
389-
|> Enum.reduce(Decimal.new(0), fn %{gas_used: gas_used}, acc ->
390-
gas_used
391-
|> Decimal.new()
392-
|> Decimal.add(acc)
391+
|> Enum.reduce(Decimal.new(0), fn transaction, acc ->
392+
gas_used = Decimal.new(transaction.gas_used)
393+
394+
# Use gas_price if available, otherwise use max_fee_per_gas
395+
effective_gas_price =
396+
if transaction.gas_price do
397+
gas_price_to_decimal(transaction.gas_price)
398+
else
399+
gas_price_to_decimal(transaction.max_fee_per_gas)
400+
end
401+
402+
if effective_gas_price do
403+
transaction_burnt_fee = gas_used
404+
|> Decimal.mult(effective_gas_price)
405+
|> Decimal.mult(Decimal.from_float(fair_burnt_fee_fraction))
406+
|> Decimal.round(0)
407+
408+
Decimal.add(transaction_burnt_fee, acc)
409+
else
410+
acc
411+
end
393412
end)
394-
|> Decimal.mult(gas_price_to_decimal(base_fee_per_gas))
413+
else
414+
# Original calculation for non-FAIR networks
415+
if is_nil(base_fee_per_gas) do
416+
Decimal.new(0)
417+
else
418+
transactions
419+
|> Enum.reduce(Decimal.new(0), fn %{gas_used: gas_used}, acc ->
420+
gas_used
421+
|> Decimal.new()
422+
|> Decimal.add(acc)
423+
end)
424+
|> Decimal.mult(gas_price_to_decimal(base_fee_per_gas))
425+
end
395426
end
396427
end
397428

apps/indexer/lib/indexer/supervisor.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,8 @@ defmodule Indexer.Supervisor do
289289
@variants_with_implemented_fetch_beneficiaries [
290290
EthereumJSONRPC.Besu,
291291
EthereumJSONRPC.Erigon,
292-
EthereumJSONRPC.Nethermind
292+
EthereumJSONRPC.Nethermind,
293+
EthereumJSONRPC.Geth
293294
]
294295

295296
defp maybe_add_block_reward_fetcher(

config/runtime.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,8 @@ config :explorer,
262262
base_fee_max_change_denominator: ConfigHelper.parse_integer_env_var("EIP_1559_BASE_FEE_MAX_CHANGE_DENOMINATOR", 8),
263263
csv_export_limit: ConfigHelper.parse_integer_env_var("CSV_EXPORT_LIMIT", 10_000),
264264
shrink_internal_transactions_enabled: ConfigHelper.parse_bool_env_var("SHRINK_INTERNAL_TRANSACTIONS_ENABLED"),
265-
replica_max_lag: ConfigHelper.parse_time_env_var("REPLICA_MAX_LAG", "5m")
265+
replica_max_lag: ConfigHelper.parse_time_env_var("REPLICA_MAX_LAG", "5m"),
266+
fair_burnt_fee_fraction: ConfigHelper.parse_float_env_var("BURNT_FEE_FRACTION", "0.5")
266267

267268
config :explorer, :proxy,
268269
caching_implementation_data_enabled: true,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[
2+
{
3+
"title": "FAIR Community",
4+
"links": [
5+
{
6+
"text": "GitHub",
7+
"url": "https://github.com/skalenetwork"
8+
},
9+
{
10+
"text": "Twitter",
11+
"url": "https://x.com/FAIR_Blockchain"
12+
}
13+
]
14+
}
15+
]
4.38 KB
Loading
46.7 KB
Loading

0 commit comments

Comments
 (0)