├── .codacy.yml
├── .dockerignore
├── .editorconfig
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ ├── release.yml
│ └── test_build.yml
├── .gitignore
├── .goreleaser.yml
├── .run
└── testnet.run.xml
├── .travis.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── COPYING.LESSER
├── Dockerfile.release
├── FUZZING.md
├── Makefile
├── PULL_REQUEST_TEMPLATE.md
├── README.md
├── _config.yml
├── appveyor.yml
├── cmd
├── cmdtest
│ └── test_cmd.go
└── opera
│ ├── launcher
│ ├── accountcmd.go
│ ├── accountcmd_test.go
│ ├── chaincmd.go
│ ├── check.go
│ ├── config.go
│ ├── config_custom.go
│ ├── config_custom_test.go
│ ├── consolecmd.go
│ ├── consolecmd_test.go
│ ├── db-transform.go
│ ├── dbcmd.go
│ ├── defaults.go
│ ├── export.go
│ ├── fake.go
│ ├── fake_test.go
│ ├── fixdirty.go
│ ├── genesiscmd.go
│ ├── import.go
│ ├── launcher.go
│ ├── metrics
│ │ └── metrics.go
│ ├── misccmd.go
│ ├── params.go
│ ├── run_test.go
│ ├── snapshotcmd.go
│ ├── testdata
│ │ ├── dupes
│ │ │ ├── 1
│ │ │ ├── 2
│ │ │ └── foo
│ │ ├── empty.js
│ │ ├── guswallet.json
│ │ ├── keystore
│ │ │ ├── .hiddenfile
│ │ │ ├── README
│ │ │ ├── UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
│ │ │ ├── aaa
│ │ │ ├── empty
│ │ │ ├── foo
│ │ │ │ └── fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e
│ │ │ ├── garbage
│ │ │ ├── no-address
│ │ │ ├── zero
│ │ │ └── zzz
│ │ ├── passwords.txt
│ │ └── wrong-passwords.txt
│ ├── testnet.go
│ ├── tracing
│ │ └── tracing.go
│ ├── usage.go
│ ├── validator.go
│ ├── validatorcmd.go
│ ├── valkeystore.go
│ ├── x1testnet.go
│ └── xenblocks.go
│ └── main.go
├── debug
├── api.go
├── flags.go
├── loudpanic.go
├── loudpanic_fallback.go
├── trace.go
└── trace_fallback.go
├── demo
├── .gitignore
├── README.md
├── _params.sh
├── clean.sh
├── start.sh
└── stop.sh
├── docker
├── Dockerfile.x1
└── networksimulator
│ ├── README.md
│ ├── generate.py
│ ├── grafana
│ ├── etc
│ │ └── grafana
│ │ │ └── provisioning
│ │ │ ├── dashboards
│ │ │ └── main.yaml
│ │ │ └── datasources
│ │ │ └── datasource.yml
│ └── var
│ │ └── lib
│ │ └── grafana
│ │ └── dashboards
│ │ ├── home.json
│ │ └── host.json
│ ├── prometheus
│ └── .gitignore
│ ├── requirements.txt
│ ├── templates
│ ├── docker-compose.yaml.j2
│ ├── grafana.conf.j2
│ └── prometheus.yml.j2
│ ├── txblaster.py
│ └── update_network_version.py
├── docs
└── validators
│ ├── README.md
│ ├── connect-wallet.png
│ └── create-validator.png
├── ethapi
├── README.md
├── abft_api.go
├── addrlock.go
├── api.go
├── backend.go
├── dag_api.go
└── transaction_args.go
├── eventcheck
├── all.go
├── ban.go
├── basiccheck
│ └── basic_check.go
├── bvallcheck
│ └── all_check.go
├── epochcheck
│ └── epoch_check.go
├── evallcheck
│ └── evallcheck.go
├── gaspowercheck
│ └── gas_power_check.go
├── heavycheck
│ ├── adapters.go
│ ├── config.go
│ └── heavy_check.go
├── parentlesscheck
│ └── parentless_check.go
└── parentscheck
│ └── parents_check.go
├── evmcore
├── .gitignore
├── apply_fake_genesis.go
├── bench_test.go
├── blocks.go
├── chain_makers.go
├── dummy_block.go
├── error.go
├── evm.go
├── gaspool.go
├── helper_test.go
├── notify.go
├── state_prefetcher.go
├── state_processor.go
├── state_transition.go
├── tx_cacher.go
├── tx_journal.go
├── tx_list.go
├── tx_list_test.go
├── tx_noncer.go
├── tx_pool.go
├── tx_pool_test.go
└── types.go
├── flags
└── helpers.go
├── ftmclient
├── dag_api.go
└── ethclient.go
├── go.mod
├── go.sum
├── gossip
├── api.go
├── apply_genesis.go
├── basiccheck_test.go
├── blockproc
│ ├── drivermodule
│ │ └── driver_txs.go
│ ├── eventmodule
│ │ └── confirmed_events_processor.go
│ ├── evmmodule
│ │ └── evm.go
│ ├── interface.go
│ ├── sealmodule
│ │ └── sealer.go
│ └── verwatcher
│ │ ├── store.go
│ │ ├── store_network_version.go
│ │ └── version_watcher.go
├── c_block_callbacks.go
├── c_block_callbacks_test.go
├── c_event_callbacks.go
├── c_llr_callbacks.go
├── c_llr_callbacks_test.go
├── checker_helpers.go
├── common_test.go
├── config.go
├── contract
│ ├── ballot
│ │ ├── Ballot.go
│ │ ├── Ballot.sol
│ │ ├── ballot.abi
│ │ └── ballot.bin
│ ├── contract.go
│ ├── driver100
│ │ └── contract.go
│ ├── driverauth100
│ │ └── contract.go
│ ├── netinit100
│ │ └── contract.go
│ ├── sfc100
│ │ └── contract.go
│ ├── sfclib100
│ │ └── contract.go
│ └── solc
│ │ └── .gitignore
├── discover.go
├── dummy_tx_pool.go
├── emitter
│ ├── config.go
│ ├── control.go
│ ├── emitter.go
│ ├── emitter_llr.go
│ ├── emitter_test.go
│ ├── hooks.go
│ ├── mock
│ │ └── world.go
│ ├── originatedtxs
│ │ └── txs_ring_buffer.go
│ ├── parents.go
│ ├── piecefuncs.go
│ ├── prev_action_files.go
│ ├── sync.go
│ ├── txs.go
│ ├── validators.go
│ └── world.go
├── emitter_world.go
├── enr_entry.go
├── eth_state_adapter.go
├── ethapi_backend.go
├── evm_state_reader.go
├── evm_test.go
├── evmstore
│ ├── apply_genesis.go
│ ├── config.go
│ ├── evmpruner
│ │ ├── bloom.go
│ │ ├── exact.go
│ │ └── pruner.go
│ ├── store.go
│ ├── store_block_cache.go
│ ├── store_receipts.go
│ ├── store_receipts_test.go
│ ├── store_test.go
│ ├── store_tx.go
│ ├── store_tx_position.go
│ └── utils.go
├── execqueue.go
├── filters
│ ├── api.go
│ ├── api_test.go
│ ├── filter.go
│ ├── filter_system.go
│ ├── filter_system_test.go
│ └── filter_test.go
├── gasprice
│ ├── constructive.go
│ ├── gasprice.go
│ ├── gasprice_test.go
│ └── reactive.go
├── gpo_backend.go
├── handler.go
├── handler_fuzz.go
├── handler_snap.go
├── heavycheck_test.go
├── mps_test.go
├── peer.go
├── peerset.go
├── proclogger
│ ├── dag_logger.go
│ └── llr_logger.go
├── protocol.go
├── protocols
│ ├── blockrecords
│ │ ├── brprocessor
│ │ │ ├── config.go
│ │ │ └── processor.go
│ │ └── brstream
│ │ │ ├── brstreamleecher
│ │ │ ├── config.go
│ │ │ └── leecher.go
│ │ │ ├── brstreamseeder
│ │ │ ├── config.go
│ │ │ └── seeder.go
│ │ │ └── types.go
│ ├── blockvotes
│ │ ├── bvprocessor
│ │ │ ├── config.go
│ │ │ └── processor.go
│ │ └── bvstream
│ │ │ ├── bvstreamleecher
│ │ │ ├── config.go
│ │ │ └── leecher.go
│ │ │ ├── bvstreamseeder
│ │ │ ├── config.go
│ │ │ └── seeder.go
│ │ │ └── types.go
│ ├── dag
│ │ └── dagstream
│ │ │ ├── dagstreamleecher
│ │ │ ├── config.go
│ │ │ ├── leecher.go
│ │ │ └── leecher_test.go
│ │ │ ├── dagstreamseeder
│ │ │ ├── config.go
│ │ │ └── seeder.go
│ │ │ └── types.go
│ ├── epochpacks
│ │ ├── epprocessor
│ │ │ ├── config.go
│ │ │ └── processor.go
│ │ └── epstream
│ │ │ ├── epstreamleecher
│ │ │ ├── config.go
│ │ │ └── leecher.go
│ │ │ ├── epstreamseeder
│ │ │ ├── config.go
│ │ │ └── seeder.go
│ │ │ └── types.go
│ └── snap
│ │ ├── api.go
│ │ ├── events.go
│ │ └── snapstream
│ │ └── snapleecher
│ │ ├── leecher.go
│ │ ├── peer.go
│ │ ├── statesync.go
│ │ └── types.go
├── randselect.go
├── service.go
├── sfc_test.go
├── store.go
├── store_activation_heights.go
├── store_block.go
├── store_decided_state.go
├── store_epoch.go
├── store_event.go
├── store_heads.go
├── store_last_bv.go
├── store_last_ev.go
├── store_last_events.go
├── store_llr_block.go
├── store_llr_epoch.go
├── store_llr_state.go
├── store_migration.go
├── sync.go
└── tflusher.go
├── integration
├── assembly.go
├── bench_db_flush_test.go
├── db.go
├── diskusage.go
├── diskusage_openbsd.go
├── diskusage_windows.go
├── legacy_migrate.go
├── makefakegenesis
│ └── genesis.go
├── makegenesis
│ └── genesis.go
├── makeoriginaltestnetgenesis
│ ├── genesis.go
│ └── rules.go
├── maketestnetgenesis
│ └── genesis.go
├── metric.go
├── metric_test.go
├── presets.go
├── routing.go
├── status.go
└── xenblocks
│ └── reporter
│ ├── stack.go
│ └── xenblocks.go
├── inter
├── block.go
├── drivertype
│ └── driver_type.go
├── event.go
├── event_serializer.go
├── event_serializer_test.go
├── event_test.go
├── events.go
├── gas_power_left.go
├── gas_power_left_test.go
├── iblockproc
│ ├── decided_state.go
│ ├── legacy.go
│ └── profiles.go
├── ibr
│ └── inter_block_records.go
├── iep
│ └── inter_epoch_packs.go
├── ier
│ └── inter_epoch_records.go
├── inter_llr.go
├── inter_llr_test.go
├── inter_mps.go
├── signature.go
├── time.go
├── transaction_serializer.go
├── transaction_serializer_test.go
└── validatorpk
│ ├── pubkey.go
│ └── pubkey_test.go
├── logger
├── instance.go
├── logger.go
├── logrus.go
├── periodic_log.go
└── test_output.go
├── opera
├── contracts
│ ├── driver
│ │ ├── driver_predeploy.go
│ │ ├── drivercall
│ │ │ └── driver_calls.go
│ │ └── driverpos
│ │ │ └── positions.go
│ ├── driverauth
│ │ └── driverauth.go
│ ├── emitterdriver
│ │ └── emitterdriver.go
│ ├── evmwriter
│ │ ├── evm_writer.go
│ │ └── evm_writer_test.go
│ ├── netinit
│ │ ├── netinitcalls
│ │ │ └── network_initializer_calls.go
│ │ └── network_initializer.go
│ ├── sfc
│ │ └── sfc_predeploy.go
│ └── sfclib
│ │ └── sfclib_predeploy.go
├── genesis
│ ├── gpos
│ │ └── validators.go
│ └── types.go
├── genesisstore
│ ├── disk.go
│ ├── filelog
│ │ └── filelog.go
│ ├── fileshash
│ │ ├── filehash_test.go
│ │ ├── reader_file.go
│ │ ├── reader_map.go
│ │ └── write_file.go
│ ├── readersmap
│ │ └── reader_map.go
│ ├── store.go
│ └── store_genesis.go
├── legacy_serialization.go
├── marshal.go
├── marshal_test.go
└── rules.go
├── sonar-project.properties
├── system
├── etc
│ ├── default
│ │ └── x1
│ └── x1
│ │ └── config.toml
├── lib
│ └── systemd
│ │ └── system
│ │ └── x1.service
├── usr
│ └── share
│ │ └── x1
│ │ └── configs
│ │ └── testnet
│ │ ├── api-node.toml
│ │ ├── archive-node.toml
│ │ ├── full-node.toml
│ │ └── validator-node.toml
├── x1-post-install.sh
└── x1-pre-install.sh
├── topicsdb
├── index.go
├── key.go
├── key_test.go
├── record.go
├── search_parallel.go
├── search_test.go
├── sync.go
├── thread_pool.go
├── topicsdb.go
└── topicsdb_test.go
├── tracing
└── tx-tracing.go
├── utils
├── adapters
│ ├── ethdb2kvdb
│ │ └── adapter.go
│ ├── kvdb2ethdb
│ │ └── adapter.go
│ ├── snap2kvdb
│ │ └── adapter.go
│ └── vecmt2dagidx
│ │ └── vecmt2lachesis.go
├── bitmap
│ └── bitset.go
├── bits
│ ├── bits.go
│ └── bits_test.go
├── concurrent
│ ├── ValidatorBlocksSet.go
│ ├── ValidatorEpochsSet.go
│ ├── ValidatorEventsSet.go
│ └── events.go
├── cser
│ ├── binary.go
│ ├── binary_test.go
│ ├── read_writer.go
│ └── read_writer_test.go
├── dbutil
│ ├── asyncflushproducer
│ │ ├── producer.go
│ │ └── store.go
│ ├── autocompact
│ │ ├── store.go
│ │ └── strategy.go
│ ├── compactdb
│ │ ├── compactdb.go
│ │ ├── keys.go
│ │ ├── keys_test.go
│ │ └── log.go
│ ├── dbcounter
│ │ └── dbcounter.go
│ ├── itergc
│ │ └── iterator_gc.go
│ ├── switchable
│ │ ├── snapshot.go
│ │ └── snapshot_test.go
│ └── threads
│ │ ├── counted.go
│ │ ├── pool.go
│ │ └── pool_test.go
├── devnullfile
│ └── devnull.go
├── errlock
│ └── errlock.go
├── eventid
│ └── eventid.go
├── fast
│ ├── buffer.go
│ └── buffer_test.go
├── file.go
├── iodb
│ └── io_db.go
├── ioread
│ └── ioread.go
├── memory
│ ├── LICENSE
│ ├── doc.go
│ ├── memory_bsd.go
│ ├── memory_darwin.go
│ ├── memory_linux.go
│ ├── memory_test.go
│ ├── memory_windows.go
│ ├── memsysctl.go
│ └── stub.go
├── migration
│ ├── id_store.go
│ ├── kvdb_id_store.go
│ ├── migration.go
│ └── migration_test.go
├── nameof.go
├── num_queue.go
├── num_queue_test.go
├── pretty_duration.go
├── pretty_duration_test.go
├── randat
│ └── rand_at.go
├── rate
│ ├── gauge.go
│ └── gauge_test.go
├── rlpstore
│ └── rlpstore.go
├── self-table.go
├── signers
│ ├── gsignercache
│ │ └── global_cache.go
│ └── internaltx
│ │ ├── internaltx.go
│ │ └── internaltx_test.go
├── spin_lock.go
├── to_ftm.go
├── txtime
│ └── txtime.go
├── uint2hash.go
├── weighted_shuffle.go
├── weighted_shuffle_test.go
└── wgmutex
│ └── wg_mutex.go
├── valkeystore
├── cache.go
├── common_test.go
├── default.go
├── encryption
│ ├── encryption.go
│ ├── io.go
│ └── migration.go
├── files.go
├── files_test.go
├── keystore.go
├── mem.go
├── mem_test.go
├── signer.go
└── sync.go
├── vecmt
├── index.go
├── index_test.go
├── median_time.go
├── median_time_test.go
├── no_cheaters.go
├── store_vectors.go
├── vector.go
└── vector_ops.go
└── version
├── version.go
└── version_test.go
/.codacy.yml:
--------------------------------------------------------------------------------
1 | ---
2 | engines:
3 | rubocop:
4 | enabled: true
5 | exclude_paths:
6 | - config/engines.yml
7 | duplication:
8 | enabled: true
9 | exclude_paths:
10 | - config/engines.yml
11 | metrics:
12 | enabled: true
13 | exclude_paths:
14 | - config/engines.yml
15 | coverage:
16 | enabled: true
17 | exclude_paths:
18 | - config/engines.yml
19 | languages:
20 | css:
21 | extensions:
22 | - '-css.resource'
23 | exclude_paths:
24 | - '.bundle/**'
25 | - 'spec/**/*'
26 | - 'benchmarks/**/*'
27 | - '*.min.js'
28 | - '**/*.pb.go'
29 | - '**/tests/**'
30 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | vendor
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 | charset = utf-8
7 |
8 | [*.go]
9 | indent_style = tab
10 | tab_width = 4
11 |
12 | [Makefile]
13 | indent_style = tab
14 |
15 | [*.yml]
16 | indent_style = space
17 | indent_size = 2
18 |
19 | [*.proto]
20 | indent_style = space
21 | indent_size = 2
22 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Golang files:
2 | *.go @andrecronje
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **Describe the bug**
8 | A clear and concise description of what the bug is.
9 |
10 | **To Reproduce**
11 | Steps to reproduce the behavior:
12 | 1. Go to '...'
13 | 2. Click on '....'
14 | 3. Scroll down to '....'
15 | 4. See error
16 |
17 | **Expected behavior**
18 | A clear and concise description of what you expected to happen.
19 |
20 | **Screenshots**
21 | If applicable, add screenshots to help explain your problem.
22 |
23 | **Desktop (please complete the following information):**
24 | - OS: [e.g. iOS]
25 | - Browser [e.g. chrome, safari]
26 | - Version [e.g. 22]
27 |
28 | **Smartphone (please complete the following information):**
29 | - Device: [e.g. iPhone6]
30 | - OS: [e.g. iOS8.1]
31 | - Browser [e.g. stock browser, safari]
32 | - Version [e.g. 22]
33 |
34 | **Additional context**
35 | Add any other context about the problem here.
36 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | **Is your feature request related to a problem? Please describe.**
8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Describe alternatives you've considered**
14 | A clear and concise description of any alternative solutions or features you've considered.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/.github/workflows/test_build.yml:
--------------------------------------------------------------------------------
1 | name: Check build
2 |
3 | on:
4 | push:
5 | pull_request:
6 | branches:
7 | - develop
8 | - master
9 |
10 | jobs:
11 | check-build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Checkout
15 | uses: actions/checkout@v3
16 |
17 | - name: Golang dependency
18 | uses: actions/setup-go@v3
19 | with:
20 | go-version: '^1.18'
21 |
22 | - name: Run unit tests
23 | run: go test ./...
24 |
25 | - name: Build
26 | run: make x1
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # MacOS
2 | .DS_Store
3 |
4 | # IDE
5 | .vscode
6 | .idea/
7 |
8 | # Go prof output
9 | *.prof
10 |
11 | # Test files
12 | *.rlp
13 |
14 | # Go test output
15 | */*.test
16 | */*.out
17 | fuzzing/
18 |
19 | # Build output
20 | build
21 | dist
22 |
23 | # Dependencies
24 | vendor
25 | glide.lock
26 |
27 | # patches and diff files
28 | *.patch
29 | *.diff
30 |
31 | # gomobile compilation output
32 | *.aar
33 | *.jar
34 |
35 | # archives
36 | *.tar.gz
37 | *.tgz
38 | *.zip
39 |
40 | # opera project specific
41 | scripts/certs
42 | scripts/nodes
43 | scripts/peers.json
44 | scripts/docker/upx
45 | nodes
46 | peers.json
47 | certs
48 | lachesis_*
49 | !*.go
50 | *.log
51 | *.graph
52 | *.gv
53 | *.finality
54 | testnet.g
55 |
56 | # Backup copies
57 | *~
58 | *.bak
59 |
60 | .#*
61 |
62 | **/coverage.txt
63 |
64 | dist/
65 | /docker/networksimulator/docker-compose.yaml
66 | /docker/networksimulator/prometheus/prometheus.yml
67 |
--------------------------------------------------------------------------------
/.run/testnet.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 |
3 | go:
4 | - 1.14.x
5 |
6 | go_import_path: github.com/Fantom-foundation/go-opera
7 |
8 | cache:
9 | directories:
10 | - $GOPATH/pkg
11 |
12 | env:
13 | global:
14 | - GO111MODULE=on
15 |
16 | # install: skip
17 |
18 | script:
19 | - go build -v ./...
20 |
21 | after_success:
22 | - |
23 | if [ -n "$GO_TEST" ]; then
24 | go test -coverprofile=coverage.txt -covermode=atomic ./...
25 | elif [ -n "$GO_INTEGRATION_TEST" ]; then
26 | go test ./integration/
27 | fi
28 |
29 | after_script:
30 | - |
31 | if [ -n "$GO_TEST" ]; then
32 | bash <(curl -s https://codecov.io/bash)
33 | fi
34 |
35 | matrix:
36 | include:
37 | - name: go test
38 | env:
39 | - GO_TEST=1
40 |
41 | - name: testnet
42 | env:
43 | - GO_INTEGRATION_TEST=1
44 |
--------------------------------------------------------------------------------
/Dockerfile.release:
--------------------------------------------------------------------------------
1 | FROM alpine:3.14
2 |
3 | RUN set -x \
4 | && apk add --update --no-cache \
5 | ca-certificates \
6 | && rm -rf /var/cache/apk/*
7 | COPY x1 /usr/local/bin/
8 |
9 | EXPOSE 18545 18546 5050
10 | ENTRYPOINT ["x1"]
11 |
--------------------------------------------------------------------------------
/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Please check if what you want to add to `go-opera` list meets [quality standards](https://github.com/Fantom-foundation/go-opera/blob/master/CONTRIBUTING.md#quality-standard) before sending pull request.
2 |
3 | **Please provide package links to:**
4 |
5 | - github.com repo:
6 | - godoc.org:
7 | - goreportcard.com:
8 | - coverage service link ([cover.run](https://cover.run/), [gocover](http://gocover.io/), [coveralls](https://coveralls.io/) etc.), example: `[](https://cover.run/go?tag=golang-1.10&repo=github.com%2Fuser%2Frepository)`
9 |
10 | **Make sure that you've checked the boxes below before you submit PR:**
11 | - [ ] I have added my package in alphabetical order.
12 | - [ ] I have an appropriate description with correct grammar.
13 | - [ ] I know that this package was not listed before.
14 | - [ ] I have added godoc link to the repo and to my pull request.
15 | - [ ] I have added coverage service link to the repo and to my pull request.
16 | - [ ] I have added goreportcard link to the repo and to my pull request.
17 | - [ ] I have read [Contribution guidelines](https://github.com/Fantom-foundation/go-opera/blob/master/CONTRIBUTING.md#contribution-guidelines), [maintainers note](https://github.com/Fantom-foundation/go-opera/blob/master/CONTRIBUTING.md#maintainers) and [Quality standard](https://github.com/Fantom-foundation/go-opera/blob/master/CONTRIBUTING.md#quality-standard).
18 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | title: Xen Crypto Documentation
2 | description: XEN is a cryptocurrency for the masses. It is designed and built to deliver on the First Principles of Crypto.
3 | url: https://docs.xen.network/
4 |
5 | author:
6 | name: Fair Crypto Foundation
7 | url: https://faircrypto.org
8 |
9 | plugins:
10 | - jekyll-remote-theme
11 | - jekyll-titles-from-headings
12 | remote_theme: FairCrypto/minima
13 | minima:
14 | skin: auto
15 | social_links:
16 | - { platform: github, user_url: "https://github.com/FairCrypto/go-x1" }
17 | - { platform: twitter, user_url: "https://twitter.com/XEN_Crypto" }
18 | - { platform: telegram, user_url: "https://t.me/XENCryptoTalk" }
19 | - { platform: youtube, user_url: "https://m.youtube.com/channel/UCiw5nyHHt9BPHvoRbcGNehA/playlists" }
20 | show_excerpts: false
21 |
22 | titles_from_headings:
23 | enabled: true
24 | strip_title: true
25 | collections: false
26 |
27 | header_pages:
28 | - index.md
29 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 0.4.5-rc1#{build}
2 | image: Visual Studio 2017
3 |
4 | build: off
5 |
6 | clone_folder: c:\gopath\src\github.com\Fantom-foundation\go-opera
7 |
8 | environment:
9 | PATH: C:\gopath\bin;C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin;C:\PROGRA~1\Git\bin;C:\PROGRA~1\Git\usr\bin\;C:\ProgramData\chocolatey\bin;$(PATH)
10 | GOPATH: c:\gopath
11 | GO111MODULE: on
12 |
13 | stack: go 1.14
14 |
15 | init:
16 | - choco install make mingw
17 |
18 | cache:
19 | - C:\usr
20 | - C:\ProgramData\chocolatey
21 |
22 | before_test:
23 | - ps: Set-NetFirewallProfile -All -Enabled False
24 | - ps: Disable-NetFirewallRule -All
25 |
26 | test_script:
27 | - go test -v ./...
28 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/fake.go:
--------------------------------------------------------------------------------
1 | package launcher
2 |
3 | import (
4 | "crypto/ecdsa"
5 | "fmt"
6 | "strconv"
7 | "strings"
8 |
9 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
10 | cli "gopkg.in/urfave/cli.v1"
11 |
12 | "github.com/Fantom-foundation/go-opera/integration/makefakegenesis"
13 | )
14 |
15 | // FakeNetFlag enables special testnet, where validators are automatically created
16 | var FakeNetFlag = cli.StringFlag{
17 | Name: "fakenet",
18 | Usage: "'n/N' - sets coinbase as fake n-th key from genesis of N validators.",
19 | }
20 |
21 | func getFakeValidatorKey(ctx *cli.Context) *ecdsa.PrivateKey {
22 | id, _, err := parseFakeGen(ctx.GlobalString(FakeNetFlag.Name))
23 | if err != nil || id == 0 {
24 | return nil
25 | }
26 | return makefakegenesis.FakeKey(id)
27 | }
28 |
29 | func parseFakeGen(s string) (id idx.ValidatorID, num idx.Validator, err error) {
30 | parts := strings.SplitN(s, "/", 2)
31 | if len(parts) != 2 {
32 | err = fmt.Errorf("use %%d/%%d format")
33 | return
34 | }
35 |
36 | var u32 uint64
37 | u32, err = strconv.ParseUint(parts[0], 10, 32)
38 | if err != nil {
39 | return
40 | }
41 | id = idx.ValidatorID(u32)
42 |
43 | u32, err = strconv.ParseUint(parts[1], 10, 32)
44 | num = idx.Validator(u32)
45 | if num < 0 || idx.Validator(id) > num {
46 | err = fmt.Errorf("key-num should be in range from 1 to validators (/), or should be zero for non-validator node")
47 | return
48 | }
49 |
50 | return
51 | }
52 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/metrics/metrics.go:
--------------------------------------------------------------------------------
1 | package metrics
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 | "sync"
7 | "sync/atomic"
8 | "time"
9 |
10 | "github.com/ethereum/go-ethereum/log"
11 | "github.com/ethereum/go-ethereum/metrics"
12 | )
13 |
14 | var once sync.Once
15 |
16 | func SetDataDir(datadir string) {
17 | once.Do(func() {
18 | go measureDbDir("db_size", datadir)
19 | })
20 | }
21 |
22 | func measureDbDir(name, datadir string) {
23 | var (
24 | dbSize int64
25 | gauge metrics.Gauge
26 | rescan = (len(datadir) > 0 && datadir != "inmemory")
27 | )
28 | for {
29 | time.Sleep(10 * time.Second)
30 |
31 | if rescan {
32 | size := sizeOfDir(datadir, new(int))
33 | atomic.StoreInt64(&dbSize, size)
34 | }
35 |
36 | if gauge == nil {
37 | gauge = metrics.NewRegisteredFunctionalGauge(name, nil, func() int64 {
38 | return atomic.LoadInt64(&dbSize)
39 | })
40 | }
41 |
42 | if !rescan {
43 | break
44 | }
45 | }
46 | }
47 |
48 | func sizeOfDir(dir string, counter *int) (size int64) {
49 | err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
50 | *counter++
51 | if *counter % 100 == 0 {
52 | time.Sleep(100 * time.Millisecond)
53 | }
54 | if err != nil {
55 | log.Debug("datadir walk", "path", path, "err", err)
56 | return filepath.SkipDir
57 | }
58 |
59 | if info.IsDir() {
60 | return nil
61 | }
62 |
63 | dst, err := filepath.EvalSymlinks(path)
64 | if err == nil && dst != path {
65 | size += sizeOfDir(dst, counter)
66 | } else {
67 | size += info.Size()
68 | }
69 |
70 | return nil
71 | })
72 |
73 | if err != nil {
74 | log.Debug("datadir walk", "path", dir, "err", err)
75 | }
76 |
77 | return
78 | }
79 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/misccmd.go:
--------------------------------------------------------------------------------
1 | package launcher
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "runtime"
7 | "strings"
8 |
9 | "github.com/ethereum/go-ethereum/cmd/utils"
10 | "github.com/ethereum/go-ethereum/params"
11 | "gopkg.in/urfave/cli.v1"
12 |
13 | "github.com/Fantom-foundation/go-opera/gossip"
14 | )
15 |
16 | var (
17 | versionCommand = cli.Command{
18 | Action: utils.MigrateFlags(version),
19 | Name: "version",
20 | Usage: "Print version numbers",
21 | ArgsUsage: " ",
22 | Category: "MISCELLANEOUS COMMANDS",
23 | Description: `
24 | The output of this command is supposed to be machine-readable.
25 | `,
26 | }
27 |
28 | licenseCommand = cli.Command{
29 | Action: utils.MigrateFlags(license),
30 | Name: "license",
31 | Usage: "Display license information",
32 | ArgsUsage: " ",
33 | Category: "MISCELLANEOUS COMMANDS",
34 | }
35 | )
36 |
37 | func version(ctx *cli.Context) error {
38 | fmt.Println(strings.Title(clientIdentifier))
39 | fmt.Println("Version:", params.VersionWithMeta())
40 | if gitCommit != "" {
41 | fmt.Println("Git Commit:", gitCommit)
42 | }
43 | if gitDate != "" {
44 | fmt.Println("Git Commit Date:", gitDate)
45 | }
46 | fmt.Println("Architecture:", runtime.GOARCH)
47 | fmt.Println("Protocol Versions:", []uint{gossip.ProtocolVersion})
48 | fmt.Println("Go Version:", runtime.Version())
49 | fmt.Println("Operating System:", runtime.GOOS)
50 | fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
51 | fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
52 | return nil
53 | }
54 |
55 | func license(_ *cli.Context) error {
56 | // TODO: license text
57 | fmt.Println(``)
58 | return nil
59 | }
60 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/dupes/1:
--------------------------------------------------------------------------------
1 | {"address":"f466859ead1932d743d622cb74fc058882e8648a","crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/dupes/2:
--------------------------------------------------------------------------------
1 | {"address":"f466859ead1932d743d622cb74fc058882e8648a","crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/dupes/foo:
--------------------------------------------------------------------------------
1 | {"address":"7ef5a6135f1fd6a02593eedc869c6d41d934aef8","crypto":{"cipher":"aes-128-ctr","ciphertext":"1d0839166e7a15b9c1333fc865d69858b22df26815ccf601b28219b6192974e1","cipherparams":{"iv":"8df6caa7ff1b00c4e871f002cb7921ed"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"e5e6ef3f4ea695f496b643ebd3f75c0aa58ef4070e90c80c5d3fb0241bf1595c"},"mac":"6d16dfde774845e4585357f24bce530528bc69f4f84e1e22880d34fa45c273e5"},"id":"950077c7-71e3-4c44-a4a1-143919141ed4","version":3}
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/empty.js:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/guswallet.json:
--------------------------------------------------------------------------------
1 | {
2 | "encseed": "26d87f5f2bf9835f9a47eefae571bc09f9107bb13d54ff12a4ec095d01f83897494cf34f7bed2ed34126ecba9db7b62de56c9d7cd136520a0427bfb11b8954ba7ac39b90d4650d3448e31185affcd74226a68f1e94b1108e6e0a4a91cdd83eba",
3 | "ethaddr": "d4584b5f6229b7be90727b0fc8c6b91bb427821f",
4 | "email": "gustav.simonsson@gmail.com",
5 | "btcaddr": "1EVknXyFC68kKNLkh6YnKzW41svSRoaAcx"
6 | }
7 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/keystore/.hiddenfile:
--------------------------------------------------------------------------------
1 | {"address":"f466859ead1932d743d622cb74fc058882e8648a","crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}
2 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/keystore/README:
--------------------------------------------------------------------------------
1 | This directory contains accounts for testing.
2 | The passphrase that unlocks them is "foobar".
3 |
4 | The "good" key files which are supposed to be loadable are:
5 |
6 | - File: UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8
7 | Address: 0x7ef5a6135f1fd6a02593eedc869c6d41d934aef8
8 | - File: aaa
9 | Address: 0xf466859ead1932d743d622cb74fc058882e8648a
10 | - File: zzz
11 | Address: 0x289d485d9771714cce91d3393d764e1311907acc
12 |
13 | The other files (including this README) are broken in various ways
14 | and should not be picked up by package accounts:
15 |
16 | - File: no-address (missing address field, otherwise same as "aaa")
17 | - File: garbage (file with random data)
18 | - File: empty (file with no content)
19 | - File: swapfile~ (should be skipped)
20 | - File: .hiddenfile (should be skipped)
21 | - File: foo/... (should be skipped because it is a directory)
22 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/keystore/UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8:
--------------------------------------------------------------------------------
1 | {"address":"7ef5a6135f1fd6a02593eedc869c6d41d934aef8","crypto":{"cipher":"aes-128-ctr","ciphertext":"1d0839166e7a15b9c1333fc865d69858b22df26815ccf601b28219b6192974e1","cipherparams":{"iv":"8df6caa7ff1b00c4e871f002cb7921ed"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"e5e6ef3f4ea695f496b643ebd3f75c0aa58ef4070e90c80c5d3fb0241bf1595c"},"mac":"6d16dfde774845e4585357f24bce530528bc69f4f84e1e22880d34fa45c273e5"},"id":"950077c7-71e3-4c44-a4a1-143919141ed4","version":3}
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/keystore/aaa:
--------------------------------------------------------------------------------
1 | {"address":"f466859ead1932d743d622cb74fc058882e8648a","crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/keystore/empty:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FairCrypto/go-x1/dd692b02e6947b8a5177dff553b05f7d5d66b670/cmd/opera/launcher/testdata/keystore/empty
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/keystore/foo/fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e:
--------------------------------------------------------------------------------
1 | {"address":"fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e","crypto":{"cipher":"aes-128-ctr","ciphertext":"8124d5134aa4a927c79fd852989e4b5419397566f04b0936a1eb1d168c7c68a5","cipherparams":{"iv":"e2febe17176414dd2cda28287947eb2f"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":4096,"p":6,"r":8,"salt":"44b415ede89f3bdd6830390a21b78965f571b347a589d1d943029f016c5e8bd5"},"mac":"5e149ff25bfd9dd45746a84bb2bcd2f015f2cbca2b6d25c5de8c29617f71fe5b"},"id":"d6ac5452-2b2c-4d3c-ad80-4bf0327d971c","version":3}
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/keystore/garbage:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FairCrypto/go-x1/dd692b02e6947b8a5177dff553b05f7d5d66b670/cmd/opera/launcher/testdata/keystore/garbage
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/keystore/no-address:
--------------------------------------------------------------------------------
1 | {"crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/keystore/zero:
--------------------------------------------------------------------------------
1 | {"address":"0000000000000000000000000000000000000000","crypto":{"cipher":"aes-128-ctr","ciphertext":"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d","cipherparams":{"iv":"dfd9ee70812add5f4b8f89d0811c9158"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1"},"mac":"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9"},"id":"472e8b3d-afb6-45b5-8111-72c89895099a","version":3}
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/keystore/zzz:
--------------------------------------------------------------------------------
1 | {"address":"289d485d9771714cce91d3393d764e1311907acc","crypto":{"cipher":"aes-128-ctr","ciphertext":"faf32ca89d286b107f5e6d842802e05263c49b78d46eac74e6109e9a963378ab","cipherparams":{"iv":"558833eec4a665a8c55608d7d503407d"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":8,"p":16,"r":8,"salt":"d571fff447ffb24314f9513f5160246f09997b857ac71348b73e785aab40dc04"},"mac":"21edb85ff7d0dab1767b9bf498f2c3cb7be7609490756bd32300bb213b59effe"},"id":"3279afcf-55ba-43ff-8997-02dcc46a6525","version":3}
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/passwords.txt:
--------------------------------------------------------------------------------
1 | foobar
2 | foobar
3 | foobar
4 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/testdata/wrong-passwords.txt:
--------------------------------------------------------------------------------
1 | wrong
2 | wrong
3 | wrong
4 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/testnet.go:
--------------------------------------------------------------------------------
1 | package launcher
2 |
3 | import (
4 | cli "gopkg.in/urfave/cli.v1"
5 | )
6 |
7 | // TestnetFlag enables special testnet, where validators are automatically created
8 | var TestnetFlag = cli.BoolFlag{
9 | Name: "testnet",
10 | Usage: "Generates X1 testnet genesis and starts the chain",
11 | }
12 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/tracing/tracing.go:
--------------------------------------------------------------------------------
1 | package tracing
2 |
3 | import (
4 | opentracing "github.com/opentracing/opentracing-go"
5 | jaegercfg "github.com/uber/jaeger-client-go/config"
6 | jaegerlog "github.com/uber/jaeger-client-go/log"
7 | "github.com/uber/jaeger-lib/metrics"
8 | "gopkg.in/urfave/cli.v1"
9 |
10 | "github.com/Fantom-foundation/go-opera/tracing"
11 | )
12 |
13 | var EnableFlag = cli.BoolFlag{
14 | Name: "tracing",
15 | Usage: "Enable traces collection and reporting",
16 | }
17 |
18 | func Start(ctx *cli.Context) (stop func(), err error) {
19 | stop = func() {}
20 |
21 | if !ctx.Bool(EnableFlag.Name) {
22 | return
23 | }
24 |
25 | var cfg *jaegercfg.Configuration
26 | cfg, err = jaegercfg.FromEnv()
27 | if err != nil {
28 | return
29 | }
30 |
31 | cfg.ServiceName = "opera"
32 |
33 | tracer, closer, err := cfg.NewTracer(
34 | jaegercfg.Logger(jaegerlog.StdLogger),
35 | jaegercfg.Metrics(metrics.NullFactory),
36 | )
37 | if err != nil {
38 | return
39 | }
40 | stop = func() {
41 | closer.Close()
42 | }
43 |
44 | opentracing.SetGlobalTracer(tracer)
45 | tracing.SetEnabled(true)
46 | return
47 | }
48 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/x1testnet.go:
--------------------------------------------------------------------------------
1 | package launcher
2 |
3 | import (
4 | "crypto/ecdsa"
5 | "github.com/Fantom-foundation/go-opera/integration/makefakegenesis"
6 | cli "gopkg.in/urfave/cli.v1"
7 | )
8 |
9 | // X1TestnetFlag enables special testnet, where validators are automatically created
10 | var X1TestnetFlag = cli.BoolFlag{
11 | Name: "x1-testnet",
12 | Usage: "Generates X1 testnet genesis and starts the chain",
13 | }
14 |
15 | func getX1ValidatorKey(ctx *cli.Context) *ecdsa.PrivateKey {
16 | return makefakegenesis.FakeKey(1)
17 | }
18 |
--------------------------------------------------------------------------------
/cmd/opera/launcher/xenblocks.go:
--------------------------------------------------------------------------------
1 | package launcher
2 |
3 | import (
4 | "fmt"
5 | cli "gopkg.in/urfave/cli.v1"
6 | "strings"
7 | )
8 |
9 | var XenBlocksEndpointFlag = cli.StringFlag{
10 | Name: "xenblocks-endpoint",
11 | Usage: "Sets the Xenblocks reporter endpoint.",
12 | }
13 |
14 | func parseXenBlocksEndpoint(s string) (url string, err error) {
15 | if !strings.HasPrefix(s, "ws://") && !strings.HasPrefix(s, "wss://") {
16 | err = fmt.Errorf("use ws:// or wss:// prefix")
17 | }
18 | return s, err
19 | }
20 |
--------------------------------------------------------------------------------
/cmd/opera/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "os"
6 |
7 | "github.com/Fantom-foundation/go-opera/cmd/opera/launcher"
8 | )
9 |
10 | func main() {
11 | if err := launcher.Launch(os.Args); err != nil {
12 | fmt.Fprintln(os.Stderr, err)
13 | os.Exit(1)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/debug/loudpanic.go:
--------------------------------------------------------------------------------
1 | // Copyright 2016 The go-ethereum Authors
2 | // This file is part of the go-ethereum library.
3 | //
4 | // The go-ethereum library is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // The go-ethereum library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU Lesser General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with the go-ethereum library. If not, see .
16 |
17 | //go:build go1.6
18 | // +build go1.6
19 |
20 | package debug
21 |
22 | import "runtime/debug"
23 |
24 | // LoudPanic panics in a way that gets all goroutine stacks printed on stderr.
25 | func LoudPanic(x interface{}) {
26 | debug.SetTraceback("all")
27 | panic(x)
28 | }
29 |
--------------------------------------------------------------------------------
/debug/loudpanic_fallback.go:
--------------------------------------------------------------------------------
1 | // Copyright 2016 The go-ethereum Authors
2 | // This file is part of the go-ethereum library.
3 | //
4 | // The go-ethereum library is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // The go-ethereum library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU Lesser General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with the go-ethereum library. If not, see .
16 |
17 | //go:build !go1.6
18 | // +build !go1.6
19 |
20 | package debug
21 |
22 | // LoudPanic panics in a way that gets all goroutine stacks printed on stderr.
23 | func LoudPanic(x interface{}) {
24 | panic(x)
25 | }
26 |
--------------------------------------------------------------------------------
/debug/trace_fallback.go:
--------------------------------------------------------------------------------
1 | // Copyright 2016 The go-ethereum Authors
2 | // This file is part of the go-ethereum library.
3 | //
4 | // The go-ethereum library is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // The go-ethereum library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU Lesser General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with the go-ethereum library. If not, see .
16 |
17 | //go:build !go1.5
18 | // +build !go1.5
19 |
20 | // no-op implementation of tracing methods for Go < 1.5.
21 |
22 | package debug
23 |
24 | import "errors"
25 |
26 | func (*HandlerT) StartGoTrace(string) error {
27 | return errors.New("tracing is not supported on Go < 1.5")
28 | }
29 |
30 | func (*HandlerT) StopGoTrace() error {
31 | return errors.New("tracing is not supported on Go < 1.5")
32 | }
33 |
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | opera*.datadir
2 | *.log
3 |
--------------------------------------------------------------------------------
/demo/_params.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | declare -ri N="${N:-3}"
4 | declare -ri M="${M:-2}"
5 | declare -r TAG="${TAG:-latest}"
6 |
7 | PORT_BASE=3000
8 | RPCP_BASE=4000
9 | WSP_BASE=4500
10 |
11 | attach_and_exec() {
12 | local i=$1
13 | local CMD=$2
14 | local RPCP=$(($RPCP_BASE+$i))
15 |
16 | for attempt in $(seq 40)
17 | do
18 | if (( attempt > 5 ))
19 | then
20 | echo " - attempt ${attempt}: " >&2
21 | fi
22 |
23 | res=$(../build/demo_opera --exec "${CMD}" attach http://127.0.0.1:${RPCP} 2> /dev/null)
24 | if [ $? -eq 0 ]
25 | then
26 | #echo "success" >&2
27 | echo $res
28 | return 0
29 | else
30 | #echo "wait" >&2
31 | sleep 1
32 | fi
33 | done
34 | echo "failed RPC connection to ${NAME}" >&2
35 | return 1
36 | }
37 |
--------------------------------------------------------------------------------
/demo/clean.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cd $(dirname $0)
3 |
4 |
5 | rm -fr opera*.datadir
6 | rm *.log
7 | rm ../build/demo_opera
8 |
--------------------------------------------------------------------------------
/demo/start.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cd $(dirname $0)
3 | . ./_params.sh
4 |
5 | set -e
6 |
7 | echo -e "\nStart $N nodes:\n"
8 |
9 | go build -o ../build/demo_opera ../cmd/opera
10 |
11 | rm -f ./transactions.rlp
12 | for ((i=0;i<$N;i+=1))
13 | do
14 | DATADIR="${PWD}/opera$i.datadir"
15 | mkdir -p ${DATADIR}
16 |
17 | PORT=$(($PORT_BASE+$i))
18 | RPCP=$(($RPCP_BASE+$i))
19 | WSP=$(($WSP_BASE+$i))
20 | ACC=$(($i+1))
21 | (../build/demo_opera \
22 | --datadir=${DATADIR} \
23 | --fakenet=${ACC}/$N \
24 | --port=${PORT} \
25 | --nat extip:127.0.0.1 \
26 | --http --http.addr="127.0.0.1" --http.port=${RPCP} --http.corsdomain="*" --http.api="eth,debug,net,admin,web3,personal,txpool,ftm,dag" \
27 | --ws --ws.addr="127.0.0.1" --ws.port=${WSP} --ws.origins="*" --ws.api="eth,debug,net,admin,web3,personal,txpool,ftm,dag" \
28 | --metrics --metrics.addr=127.0.0.1 --metrics.port=$(($RPCP+1100)) \
29 | --verbosity=3 --tracing >> opera$i.log 2>&1)&
30 |
31 | echo -e "\tnode$i ok"
32 | done
33 |
34 | echo -e "\nConnect nodes to ring:\n"
35 | for ((i=0;i<$N;i+=1))
36 | do
37 | for ((n=0;n<$M;n+=1))
38 | do
39 | j=$(((i+n+1) % N))
40 |
41 | enode=$(attach_and_exec $j 'admin.nodeInfo.enode')
42 | echo " p2p address = ${enode}"
43 |
44 | echo " connecting node-$i to node-$j:"
45 | res=$(attach_and_exec $i "admin.addPeer(${enode})")
46 | echo " result = ${res}"
47 | done
48 | done
49 |
--------------------------------------------------------------------------------
/demo/stop.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | killall demo_opera
4 |
--------------------------------------------------------------------------------
/docker/Dockerfile.x1:
--------------------------------------------------------------------------------
1 | FROM golang:alpine3.19 as builder
2 |
3 | RUN apk add --no-cache make gcc musl-dev linux-headers git
4 |
5 | WORKDIR /go/go-x1
6 | COPY . .
7 |
8 | ARG GOPROXY
9 | RUN go mod download
10 | RUN make x1
11 |
12 |
13 |
14 | FROM alpine:latest
15 |
16 | RUN apk add --no-cache ca-certificates
17 |
18 | COPY --from=builder /go/go-x1/build/x1 /
19 |
20 | EXPOSE 5050 8545 8546
21 |
22 | ENTRYPOINT ["/x1"]
23 |
--------------------------------------------------------------------------------
/docker/networksimulator/grafana/etc/grafana/provisioning/dashboards/main.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: 1
2 |
3 | providers:
4 | - name: "Dashboard provider"
5 | orgId: 1
6 | type: file
7 | disableDeletion: false
8 | updateIntervalSeconds: 10
9 | allowUiUpdates: false
10 | editable: true
11 | options:
12 | path: /var/lib/grafana/dashboards
13 | foldersFromFilesStructure: true
14 |
--------------------------------------------------------------------------------
/docker/networksimulator/grafana/etc/grafana/provisioning/datasources/datasource.yml:
--------------------------------------------------------------------------------
1 | apiVersion: 1
2 |
3 | datasources:
4 | - name: Prometheus
5 | type: prometheus
6 | url: http://prometheus:9090
7 | isDefault: true
8 | access: proxy
9 | editable: true
10 |
--------------------------------------------------------------------------------
/docker/networksimulator/prometheus/.gitignore:
--------------------------------------------------------------------------------
1 | prometheus.yml
2 |
--------------------------------------------------------------------------------
/docker/networksimulator/requirements.txt:
--------------------------------------------------------------------------------
1 | jinja2
2 | web3
3 |
--------------------------------------------------------------------------------
/docker/networksimulator/templates/grafana.conf.j2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FairCrypto/go-x1/dd692b02e6947b8a5177dff553b05f7d5d66b670/docker/networksimulator/templates/grafana.conf.j2
--------------------------------------------------------------------------------
/docker/networksimulator/templates/prometheus.yml.j2:
--------------------------------------------------------------------------------
1 | global:
2 | scrape_interval: 15s
3 | scrape_timeout: 10s
4 | evaluation_interval: 15s
5 |
6 | scrape_configs:
7 | - job_name: x1
8 | honor_timestamps: true
9 | scrape_interval: 15s
10 | scrape_timeout: 10s
11 | metrics_path: /debug/metrics/prometheus
12 | scheme: http
13 | static_configs:
14 | - targets:
15 | {% for node in nodes %}
16 | - node{{ node.id }}:6060{% endfor %}
17 |
18 | - job_name: prometheus
19 | honor_timestamps: true
20 | scrape_interval:
21 | static_configs:
22 | - targets:
23 | - node-exporter:9100
24 |
--------------------------------------------------------------------------------
/docs/validators/connect-wallet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FairCrypto/go-x1/dd692b02e6947b8a5177dff553b05f7d5d66b670/docs/validators/connect-wallet.png
--------------------------------------------------------------------------------
/docs/validators/create-validator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FairCrypto/go-x1/dd692b02e6947b8a5177dff553b05f7d5d66b670/docs/validators/create-validator.png
--------------------------------------------------------------------------------
/ethapi/README.md:
--------------------------------------------------------------------------------
1 | Package is a full copy of github.com/ethereum/go-ethereum/internal/ethapi
--------------------------------------------------------------------------------
/ethapi/addrlock.go:
--------------------------------------------------------------------------------
1 | // Copyright 2017 The go-ethereum Authors
2 | // This file is part of the go-ethereum library.
3 | //
4 | // The go-ethereum library is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // The go-ethereum library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU Lesser General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with the go-ethereum library. If not, see .
16 |
17 | package ethapi
18 |
19 | import (
20 | "sync"
21 |
22 | "github.com/ethereum/go-ethereum/common"
23 | )
24 |
25 | type AddrLocker struct {
26 | mu sync.Mutex
27 | locks map[common.Address]*sync.Mutex
28 | }
29 |
30 | // lock returns the lock of the given address.
31 | func (l *AddrLocker) lock(address common.Address) *sync.Mutex {
32 | l.mu.Lock()
33 | defer l.mu.Unlock()
34 | if l.locks == nil {
35 | l.locks = make(map[common.Address]*sync.Mutex)
36 | }
37 | if _, ok := l.locks[address]; !ok {
38 | l.locks[address] = new(sync.Mutex)
39 | }
40 | return l.locks[address]
41 | }
42 |
43 | // LockAddr locks an account's mutex. This is used to prevent another tx getting the
44 | // same nonce until the lock is released. The mutex prevents the (an identical nonce) from
45 | // being read again during the time that the first transaction is being signed.
46 | func (l *AddrLocker) LockAddr(address common.Address) {
47 | l.lock(address).Lock()
48 | }
49 |
50 | // UnlockAddr unlocks the mutex of the given account.
51 | func (l *AddrLocker) UnlockAddr(address common.Address) {
52 | l.lock(address).Unlock()
53 | }
54 |
--------------------------------------------------------------------------------
/eventcheck/all.go:
--------------------------------------------------------------------------------
1 | package eventcheck
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/eventcheck/basiccheck"
5 | "github.com/Fantom-foundation/go-opera/eventcheck/epochcheck"
6 | "github.com/Fantom-foundation/go-opera/eventcheck/gaspowercheck"
7 | "github.com/Fantom-foundation/go-opera/eventcheck/heavycheck"
8 | "github.com/Fantom-foundation/go-opera/eventcheck/parentscheck"
9 | "github.com/Fantom-foundation/go-opera/inter"
10 | )
11 |
12 | // Checkers is collection of all the checkers
13 | type Checkers struct {
14 | Basiccheck *basiccheck.Checker
15 | Epochcheck *epochcheck.Checker
16 | Parentscheck *parentscheck.Checker
17 | Gaspowercheck *gaspowercheck.Checker
18 | Heavycheck *heavycheck.Checker
19 | }
20 |
21 | // Validate runs all the checks except Poset-related
22 | func (v *Checkers) Validate(e inter.EventPayloadI, parents inter.EventIs) error {
23 | if err := v.Basiccheck.Validate(e); err != nil {
24 | return err
25 | }
26 | if err := v.Epochcheck.Validate(e); err != nil {
27 | return err
28 | }
29 | if err := v.Parentscheck.Validate(e, parents); err != nil {
30 | return err
31 | }
32 | var selfParent inter.EventI
33 | if e.SelfParent() != nil {
34 | selfParent = parents[0]
35 | }
36 | if err := v.Gaspowercheck.Validate(e, selfParent); err != nil {
37 | return err
38 | }
39 | if err := v.Heavycheck.ValidateEvent(e); err != nil {
40 | return err
41 | }
42 | return nil
43 | }
44 |
--------------------------------------------------------------------------------
/eventcheck/ban.go:
--------------------------------------------------------------------------------
1 | package eventcheck
2 |
3 | import (
4 | "errors"
5 |
6 | base "github.com/Fantom-foundation/lachesis-base/eventcheck"
7 |
8 | "github.com/Fantom-foundation/go-opera/eventcheck/epochcheck"
9 | "github.com/Fantom-foundation/go-opera/eventcheck/heavycheck"
10 | )
11 |
12 | var (
13 | ErrAlreadyProcessedBVs = errors.New("BVs is processed already")
14 | ErrAlreadyProcessedBR = errors.New("BR is processed already")
15 | ErrAlreadyProcessedEV = errors.New("EV is processed already")
16 | ErrAlreadyProcessedER = errors.New("ER is processed already")
17 | ErrUnknownEpochBVs = heavycheck.ErrUnknownEpochBVs
18 | ErrUnknownEpochEV = heavycheck.ErrUnknownEpochEV
19 | ErrUndecidedBR = errors.New("BR is unprocessable yet")
20 | ErrUndecidedER = errors.New("ER is unprocessable yet")
21 | ErrAlreadyConnectedEvent = base.ErrAlreadyConnectedEvent
22 | ErrSpilledEvent = base.ErrSpilledEvent
23 | ErrDuplicateEvent = base.ErrDuplicateEvent
24 | )
25 |
26 | func IsBan(err error) bool {
27 | if err == epochcheck.ErrNotRelevant ||
28 | err == ErrAlreadyConnectedEvent ||
29 | err == ErrAlreadyProcessedBVs ||
30 | err == ErrAlreadyProcessedBR ||
31 | err == ErrAlreadyProcessedEV ||
32 | err == ErrAlreadyProcessedER ||
33 | err == ErrUnknownEpochBVs ||
34 | err == ErrUndecidedBR ||
35 | err == ErrUnknownEpochEV ||
36 | err == ErrUndecidedER ||
37 | err == ErrSpilledEvent ||
38 | err == ErrDuplicateEvent {
39 | return false
40 | }
41 | return err != nil
42 | }
43 |
--------------------------------------------------------------------------------
/eventcheck/bvallcheck/all_check.go:
--------------------------------------------------------------------------------
1 | package bvallcheck
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/inter"
5 | )
6 |
7 | type Checker struct {
8 | HeavyCheck HeavyCheck
9 | LightCheck LightCheck
10 | }
11 |
12 | type LightCheck func(bvs inter.LlrSignedBlockVotes) error
13 |
14 | type HeavyCheck interface {
15 | Enqueue(bvs inter.LlrSignedBlockVotes, checked func(error)) error
16 | }
17 |
18 | type Callback struct {
19 | HeavyCheck HeavyCheck
20 | LightCheck LightCheck
21 | }
22 |
23 | // Enqueue tries to fill gaps the fetcher's future import queue.
24 | func (c *Checker) Enqueue(bvs inter.LlrSignedBlockVotes, checked func(error)) {
25 | // Run light checks right away
26 | err := c.LightCheck(bvs)
27 | if err != nil {
28 | checked(err)
29 | return
30 | }
31 |
32 | // Run heavy check in parallel
33 | _ = c.HeavyCheck.Enqueue(bvs, checked)
34 | }
35 |
--------------------------------------------------------------------------------
/eventcheck/evallcheck/evallcheck.go:
--------------------------------------------------------------------------------
1 | package evallcheck
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/inter"
5 | )
6 |
7 | type Checker struct {
8 | HeavyCheck HeavyCheck
9 | LightCheck LightCheck
10 | }
11 |
12 | type LightCheck func(evs inter.LlrSignedEpochVote) error
13 |
14 | type HeavyCheck interface {
15 | Enqueue(evs inter.LlrSignedEpochVote, checked func(error)) error
16 | }
17 |
18 | type Callback struct {
19 | HeavyCheck HeavyCheck
20 | LightCheck LightCheck
21 | }
22 |
23 | // Enqueue tries to fill gaps the fetcher's future import queue.
24 | func (c *Checker) Enqueue(evs inter.LlrSignedEpochVote, checked func(error)) {
25 | // Run light checks right away
26 | err := c.LightCheck(evs)
27 | if err != nil {
28 | checked(err)
29 | return
30 | }
31 |
32 | // Run heavy check in parallel
33 | _ = c.HeavyCheck.Enqueue(evs, checked)
34 | }
35 |
--------------------------------------------------------------------------------
/eventcheck/heavycheck/adapters.go:
--------------------------------------------------------------------------------
1 | package heavycheck
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/inter/dag"
5 |
6 | "github.com/Fantom-foundation/go-opera/inter"
7 | )
8 |
9 | type EventsOnly struct {
10 | *Checker
11 | }
12 |
13 | func (c *EventsOnly) Enqueue(e dag.Event, onValidated func(error)) error {
14 | return c.Checker.EnqueueEvent(e.(inter.EventPayloadI), onValidated)
15 | }
16 |
17 | type BVsOnly struct {
18 | *Checker
19 | }
20 |
21 | func (c *BVsOnly) Enqueue(bvs inter.LlrSignedBlockVotes, onValidated func(error)) error {
22 | return c.Checker.EnqueueBVs(bvs, onValidated)
23 | }
24 |
25 | type EVOnly struct {
26 | *Checker
27 | }
28 |
29 | func (c *EVOnly) Enqueue(ers inter.LlrSignedEpochVote, onValidated func(error)) error {
30 | return c.Checker.EnqueueEV(ers, onValidated)
31 | }
32 |
--------------------------------------------------------------------------------
/eventcheck/heavycheck/config.go:
--------------------------------------------------------------------------------
1 | package heavycheck
2 |
3 | type Config struct {
4 | MaxQueuedTasks int // the maximum number of tasks to queue up
5 | Threads int
6 | }
7 |
8 | func DefaultConfig() Config {
9 | return Config{
10 | MaxQueuedTasks: 1024,
11 | Threads: 0,
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/eventcheck/parentlesscheck/parentless_check.go:
--------------------------------------------------------------------------------
1 | package parentlesscheck
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/inter/dag"
5 | )
6 |
7 | type Checker struct {
8 | HeavyCheck HeavyCheck
9 | LightCheck LightCheck
10 | }
11 |
12 | type LightCheck func(dag.Event) error
13 |
14 | type HeavyCheck interface {
15 | Enqueue(e dag.Event, checked func(error)) error
16 | }
17 |
18 | // Enqueue tries to fill gaps the fetcher's future import queue.
19 | func (c *Checker) Enqueue(e dag.Event, checked func(error)) {
20 | // Run light checks right away
21 | err := c.LightCheck(e)
22 | if err != nil {
23 | checked(err)
24 | return
25 | }
26 |
27 | // Run heavy check in parallel
28 | _ = c.HeavyCheck.Enqueue(e, checked)
29 | }
30 |
--------------------------------------------------------------------------------
/eventcheck/parentscheck/parents_check.go:
--------------------------------------------------------------------------------
1 | package parentscheck
2 |
3 | import (
4 | "errors"
5 |
6 | base "github.com/Fantom-foundation/lachesis-base/eventcheck/parentscheck"
7 |
8 | "github.com/Fantom-foundation/go-opera/inter"
9 | )
10 |
11 | var (
12 | ErrPastTime = errors.New("event has lower claimed time than self-parent")
13 | )
14 |
15 | // Checker which require only parents list + current epoch info
16 | type Checker struct {
17 | base *base.Checker
18 | }
19 |
20 | // New validator which performs checks, which require known the parents
21 | func New() *Checker {
22 | return &Checker{
23 | base: &base.Checker{},
24 | }
25 | }
26 |
27 | // Validate event
28 | func (v *Checker) Validate(e inter.EventI, parents inter.EventIs) error {
29 | if err := v.base.Validate(e, parents.Bases()); err != nil {
30 | return err
31 | }
32 |
33 | if e.SelfParent() != nil {
34 | selfParent := parents[0]
35 | if !e.IsSelfParent(selfParent.ID()) {
36 | // sanity check, self-parent is always first, it's how it's stored
37 | return base.ErrWrongSelfParent
38 | }
39 | // selfParent time
40 | if e.CreationTime() <= selfParent.CreationTime() {
41 | return ErrPastTime
42 | }
43 | }
44 |
45 | return nil
46 | }
47 |
--------------------------------------------------------------------------------
/evmcore/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 | #
3 | # If you find yourself ignoring temporary files generated by your text editor
4 | # or operating system, you probably want to add a global ignore instead:
5 | # git config --global core.excludesfile ~/.gitignore_global
6 |
7 | /tmp
8 | */**/*un~
9 | *un~
10 | .DS_Store
11 | */**/.DS_Store
12 |
13 |
--------------------------------------------------------------------------------
/evmcore/blocks.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The go-ethereum Authors
2 | // This file is part of the go-ethereum library.
3 | //
4 | // The go-ethereum library is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // The go-ethereum library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU Lesser General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with the go-ethereum library. If not, see .
16 |
17 | package evmcore
18 |
19 | import (
20 | "github.com/ethereum/go-ethereum/common"
21 | )
22 |
23 | // BadHashes represent a set of manually tracked bad hashes (usually hard forks)
24 | var BadHashes = map[common.Hash]bool{}
25 |
--------------------------------------------------------------------------------
/evmcore/gaspool.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The go-ethereum Authors
2 | // This file is part of the go-ethereum library.
3 | //
4 | // The go-ethereum library is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // The go-ethereum library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU Lesser General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with the go-ethereum library. If not, see .
16 |
17 | package evmcore
18 |
19 | import (
20 | "fmt"
21 | "math"
22 | )
23 |
24 | // GasPool tracks the amount of gas available during execution of the transactions
25 | // in a block. The zero value is a pool with zero gas available.
26 | type GasPool uint64
27 |
28 | // AddGas makes gas available for execution.
29 | func (gp *GasPool) AddGas(amount uint64) *GasPool {
30 | if uint64(*gp) > math.MaxUint64-amount {
31 | panic("gas pool pushed above uint64")
32 | }
33 | *(*uint64)(gp) += amount
34 | return gp
35 | }
36 |
37 | // SubGas deducts the given amount from the pool if enough gas is
38 | // available and returns an error otherwise.
39 | func (gp *GasPool) SubGas(amount uint64) error {
40 | if uint64(*gp) < amount {
41 | return ErrGasLimitReached
42 | }
43 | *(*uint64)(gp) -= amount
44 | return nil
45 | }
46 |
47 | // Gas returns the amount of gas remaining in the pool.
48 | func (gp *GasPool) Gas() uint64 {
49 | return uint64(*gp)
50 | }
51 |
52 | func (gp *GasPool) String() string {
53 | return fmt.Sprintf("%d", *gp)
54 | }
55 |
--------------------------------------------------------------------------------
/evmcore/notify.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The go-ethereum Authors
2 | // This file is part of the go-ethereum library.
3 | //
4 | // The go-ethereum library is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // The go-ethereum library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU Lesser General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with the go-ethereum library. If not, see .
16 |
17 | package evmcore
18 |
19 | import (
20 | "github.com/ethereum/go-ethereum/common"
21 | "github.com/ethereum/go-ethereum/core/types"
22 | )
23 |
24 | // NewTxsNotify is posted when a batch of transactions enter the transaction pool.
25 | type NewTxsNotify struct{ Txs []*types.Transaction }
26 |
27 | // PendingLogsNotify is posted pre mining and notifies of pending logs.
28 | type PendingLogsNotify struct {
29 | Logs []*types.Log
30 | }
31 |
32 | // NewMinedBlockNotify is posted when a block has been imported.
33 | type NewMinedBlockNotify struct{ Block *EvmBlock }
34 |
35 | // RemovedLogsNotify is posted when a reorg happens
36 | type RemovedLogsNotify struct{ Logs []*types.Log }
37 |
38 | type ChainNotify struct {
39 | Block *EvmBlock
40 | Hash common.Hash
41 | Logs []*types.Log
42 | }
43 |
44 | type ChainSideNotify struct {
45 | Block *EvmBlock
46 | }
47 |
48 | type ChainHeadNotify struct{ Block *EvmBlock }
49 |
--------------------------------------------------------------------------------
/ftmclient/ethclient.go:
--------------------------------------------------------------------------------
1 | package ftmclient
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/ethereum/go-ethereum/ethclient"
7 | "github.com/ethereum/go-ethereum/rpc"
8 | )
9 |
10 | // Client extends Ethereum API client with typed wrappers for the FTM API.
11 | type Client struct {
12 | ethclient.Client
13 | c *rpc.Client
14 | }
15 |
16 | // Dial connects a client to the given URL.
17 | func Dial(rawurl string) (*Client, error) {
18 | return DialContext(context.Background(), rawurl)
19 | }
20 |
21 | func DialContext(ctx context.Context, rawurl string) (*Client, error) {
22 | c, err := rpc.DialContext(ctx, rawurl)
23 | if err != nil {
24 | return nil, err
25 | }
26 | return NewClient(c), nil
27 | }
28 |
29 | // NewClient creates a client that uses the given RPC client.
30 | func NewClient(c *rpc.Client) *Client {
31 | return &Client{
32 | Client: *ethclient.NewClient(c),
33 | c: c,
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/gossip/api.go:
--------------------------------------------------------------------------------
1 | package gossip
2 |
3 | import (
4 | "github.com/ethereum/go-ethereum/common"
5 | "github.com/ethereum/go-ethereum/common/hexutil"
6 | )
7 |
8 | // PublicEthereumAPI provides an API to access Ethereum-like information.
9 | // It is a github.com/ethereum/go-ethereum/eth simulation for console.
10 | type PublicEthereumAPI struct {
11 | s *Service
12 | }
13 |
14 | // NewPublicEthereumAPI creates a new Ethereum protocol API for gossip.
15 | func NewPublicEthereumAPI(s *Service) *PublicEthereumAPI {
16 | return &PublicEthereumAPI{s}
17 | }
18 |
19 | // Etherbase returns the zero address for web3 compatibility
20 | func (api *PublicEthereumAPI) Etherbase() (common.Address, error) {
21 | return common.Address{}, nil
22 | }
23 |
24 | // Coinbase returns the zero address for web3 compatibility
25 | func (api *PublicEthereumAPI) Coinbase() (common.Address, error) {
26 | return common.Address{}, nil
27 | }
28 |
29 | // Hashrate returns the zero POW hashrate for web3 compatibility
30 | func (api *PublicEthereumAPI) Hashrate() hexutil.Uint64 {
31 | return hexutil.Uint64(0)
32 | }
33 |
34 | // ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config.
35 | func (api *PublicEthereumAPI) ChainId() hexutil.Uint64 {
36 | return hexutil.Uint64(api.s.store.GetRules().NetworkID)
37 | }
38 |
--------------------------------------------------------------------------------
/gossip/blockproc/verwatcher/store.go:
--------------------------------------------------------------------------------
1 | package verwatcher
2 |
3 | import (
4 | "sync/atomic"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/kvdb"
7 |
8 | "github.com/Fantom-foundation/go-opera/logger"
9 | )
10 |
11 | // Store is a node persistent storage working over physical key-value database.
12 | type Store struct {
13 | mainDB kvdb.Store
14 |
15 | cache struct {
16 | networkVersion atomic.Value
17 | missedVersion atomic.Value
18 | }
19 |
20 | logger.Instance
21 | }
22 |
23 | // NewStore creates store over key-value db.
24 | func NewStore(mainDB kvdb.Store) *Store {
25 | s := &Store{
26 | mainDB: mainDB,
27 | Instance: logger.New("verwatcher-store"),
28 | }
29 |
30 | return s
31 | }
32 |
--------------------------------------------------------------------------------
/gossip/blockproc/verwatcher/store_network_version.go:
--------------------------------------------------------------------------------
1 | package verwatcher
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/common/bigendian"
5 | )
6 |
7 | const (
8 | nvKey = "v"
9 | mvKey = "m"
10 | )
11 |
12 | // SetNetworkVersion stores network version.
13 | func (s *Store) SetNetworkVersion(v uint64) {
14 | s.cache.networkVersion.Store(v)
15 | err := s.mainDB.Put([]byte(nvKey), bigendian.Uint64ToBytes(v))
16 | if err != nil {
17 | s.Log.Crit("Failed to put key", "err", err)
18 | }
19 | }
20 |
21 | // GetNetworkVersion returns stored network version.
22 | func (s *Store) GetNetworkVersion() uint64 {
23 | if v := s.cache.networkVersion.Load(); v != nil {
24 | return v.(uint64)
25 | }
26 | valBytes, err := s.mainDB.Get([]byte(nvKey))
27 | if err != nil {
28 | s.Log.Crit("Failed to get key", "err", err)
29 | }
30 | v := uint64(0)
31 | if valBytes != nil {
32 | v = bigendian.BytesToUint64(valBytes)
33 | }
34 | s.cache.networkVersion.Store(v)
35 | return v
36 | }
37 |
38 | // SetMissedVersion stores non-supported network upgrade.
39 | func (s *Store) SetMissedVersion(v uint64) {
40 | s.cache.missedVersion.Store(v)
41 | err := s.mainDB.Put([]byte(mvKey), bigendian.Uint64ToBytes(v))
42 | if err != nil {
43 | s.Log.Crit("Failed to put key", "err", err)
44 | }
45 | }
46 |
47 | // GetMissedVersion returns stored non-supported network upgrade.
48 | func (s *Store) GetMissedVersion() uint64 {
49 | if v := s.cache.missedVersion.Load(); v != nil {
50 | return v.(uint64)
51 | }
52 | valBytes, err := s.mainDB.Get([]byte(mvKey))
53 | if err != nil {
54 | s.Log.Crit("Failed to get key", "err", err)
55 | }
56 | v := uint64(0)
57 | if valBytes != nil {
58 | v = bigendian.BytesToUint64(valBytes)
59 | }
60 | s.cache.missedVersion.Store(v)
61 | return v
62 | }
63 |
--------------------------------------------------------------------------------
/gossip/c_block_callbacks_test.go:
--------------------------------------------------------------------------------
1 | package gossip
2 |
3 | import (
4 | "fmt"
5 | "math/big"
6 | "testing"
7 |
8 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
9 | "github.com/ethereum/go-ethereum/core/types"
10 | "github.com/stretchr/testify/require"
11 |
12 | "github.com/Fantom-foundation/go-opera/logger"
13 | "github.com/Fantom-foundation/go-opera/utils"
14 | )
15 |
16 | func TestConsensusCallback(t *testing.T) {
17 | logger.SetTestMode(t)
18 | require := require.New(t)
19 |
20 | const rounds = 30
21 |
22 | const validatorsNum = 3
23 |
24 | env := newTestEnv(2, validatorsNum)
25 | defer env.Close()
26 |
27 | // save start balances
28 | balances := make([]*big.Int, validatorsNum)
29 | for i := range balances {
30 | balances[i] = env.State().GetBalance(env.Address(idx.ValidatorID(i + 1)))
31 | }
32 |
33 | for n := uint64(0); n < rounds; n++ {
34 | // transfers
35 | txs := make([]*types.Transaction, validatorsNum)
36 | for i := idx.Validator(0); i < validatorsNum; i++ {
37 | from := i % validatorsNum
38 | to := 0
39 | txs[i] = env.Transfer(idx.ValidatorID(from+1), idx.ValidatorID(to+1), utils.ToFtm(100))
40 | }
41 | tm := sameEpoch
42 | if n%10 == 0 {
43 | tm = nextEpoch
44 | }
45 | rr, err := env.ApplyTxs(tm, txs...)
46 | require.NoError(err)
47 | // subtract fees
48 | for i, r := range rr {
49 | fee := big.NewInt(0).Mul(new(big.Int).SetUint64(r.GasUsed), txs[i].GasPrice())
50 | balances[i] = big.NewInt(0).Sub(balances[i], fee)
51 | }
52 | // balance movements
53 | balances[0].Add(balances[0], utils.ToFtm(200))
54 | balances[1].Sub(balances[1], utils.ToFtm(100))
55 | balances[2].Sub(balances[2], utils.ToFtm(100))
56 | }
57 |
58 | // check balances
59 | for i := range balances {
60 | require.Equal(
61 | balances[i],
62 | env.State().GetBalance(env.Address(idx.ValidatorID(i+1))),
63 | fmt.Sprintf("account%d", i),
64 | )
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/gossip/contract/ballot/ballot.abi:
--------------------------------------------------------------------------------
1 | [{"inputs":[{"internalType":"bytes32[]","name":"proposalNames","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"voteCount","type":"uint256"}],"name":"NewProposal","type":"event"},{"inputs":[],"name":"chairperson","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"voter","type":"address"}],"name":"giveRightToVote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"proposals","outputs":[{"internalType":"bytes32","name":"name","type":"bytes32"},{"internalType":"uint256","name":"voteCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposal","type":"uint256"}],"name":"vote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"voters","outputs":[{"internalType":"uint256","name":"weight","type":"uint256"},{"internalType":"bool","name":"voted","type":"bool"},{"internalType":"address","name":"delegate","type":"address"},{"internalType":"uint256","name":"vote","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"winnerName","outputs":[{"internalType":"bytes32","name":"winnerName_","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"winningProposal","outputs":[{"internalType":"uint256","name":"winningProposal_","type":"uint256"}],"stateMutability":"view","type":"function"}]
--------------------------------------------------------------------------------
/gossip/contract/solc/.gitignore:
--------------------------------------------------------------------------------
1 | *.json
2 | *.abi
3 | *.bin
4 | *.bin-runtime
5 |
--------------------------------------------------------------------------------
/gossip/emitter/originatedtxs/txs_ring_buffer.go:
--------------------------------------------------------------------------------
1 | package originatedtxs
2 |
3 | import (
4 | "github.com/ethereum/go-ethereum/common"
5 | "github.com/hashicorp/golang-lru/simplelru"
6 | )
7 |
8 | type Buffer struct {
9 | senderCount *simplelru.LRU // sender address -> number of transactions
10 | }
11 |
12 | func New(maxAddresses int) *Buffer {
13 | ring := &Buffer{}
14 | ring.senderCount, _ = simplelru.NewLRU(maxAddresses, nil)
15 | return ring
16 | }
17 |
18 | // Inc is not safe for concurrent use
19 | func (ring *Buffer) Inc(sender common.Address) {
20 | cur, ok := ring.senderCount.Peek(sender)
21 | if ok {
22 | ring.senderCount.Add(sender, cur.(int)+1)
23 | } else {
24 | ring.senderCount.Add(sender, int(1))
25 | }
26 | }
27 |
28 | // Dec is not safe for concurrent use
29 | func (ring *Buffer) Dec(sender common.Address) {
30 | cur, ok := ring.senderCount.Peek(sender)
31 | if !ok {
32 | return
33 | }
34 | if cur.(int) <= 1 {
35 | ring.senderCount.Remove(sender)
36 | } else {
37 | ring.senderCount.Add(sender, cur.(int)-1)
38 | }
39 | }
40 |
41 | // Clear is not safe for concurrent use
42 | func (ring *Buffer) Clear() {
43 | ring.senderCount.Purge()
44 | }
45 |
46 | // TotalOf is not safe for concurrent use
47 | func (ring *Buffer) TotalOf(sender common.Address) int {
48 | cur, ok := ring.senderCount.Get(sender)
49 | if !ok {
50 | return 0
51 | }
52 | return cur.(int)
53 | }
54 |
55 | // Empty is not safe for concurrent use
56 | func (ring *Buffer) Empty() bool {
57 | return ring.senderCount.Len() == 0
58 | }
59 |
--------------------------------------------------------------------------------
/gossip/enr_entry.go:
--------------------------------------------------------------------------------
1 | package gossip
2 |
3 | import (
4 | "github.com/ethereum/go-ethereum/core/forkid"
5 | "github.com/ethereum/go-ethereum/rlp"
6 | )
7 |
8 | // Enr is ENR entry which advertises eth protocol
9 | // on the discovery network.
10 | type Enr struct {
11 | ForkID forkid.ID
12 | // Ignore additional fields (for forward compatibility).
13 | Rest []rlp.RawValue `rlp:"tail"`
14 | }
15 |
16 | // ENRKey implements enr.Entry.
17 | func (e Enr) ENRKey() string {
18 | return "opera"
19 | }
20 |
21 | func (s *Service) currentEnr() *Enr {
22 | return &Enr{}
23 | }
24 |
--------------------------------------------------------------------------------
/gossip/eth_state_adapter.go:
--------------------------------------------------------------------------------
1 | package gossip
2 |
3 | import (
4 | "github.com/ethereum/go-ethereum/common"
5 | "github.com/ethereum/go-ethereum/core/state"
6 | "github.com/ethereum/go-ethereum/core/state/snapshot"
7 | )
8 |
9 | // ethBlockChain wraps store to implement eth/protocols/snap.BlockChain interface.
10 | type ethBlockChain struct {
11 | store *Store
12 | }
13 |
14 | func newEthBlockChain(s *Store) (*ethBlockChain, error) {
15 | bc := ðBlockChain{
16 | store: s,
17 | }
18 |
19 | return bc, nil
20 | }
21 |
22 | // StateCache returns the caching database underpinning the blockchain instance.
23 | func (bc *ethBlockChain) StateCache() state.Database {
24 | return bc.store.LastKvdbEvmSnapshot().EvmState
25 | }
26 |
27 | // ContractCode retrieves a blob of data associated with a contract hash
28 | // either from ephemeral in-memory cache, or from persistent storage.
29 | func (bc *ethBlockChain) ContractCode(hash common.Hash) ([]byte, error) {
30 | return bc.store.LastKvdbEvmSnapshot().EvmState.ContractCode(common.Hash{}, hash)
31 | }
32 |
33 | // Snapshots returns the blockchain snapshot tree to paused it during sync.
34 | func (bc *ethBlockChain) Snapshots() *snapshot.Tree {
35 | return bc.store.LastKvdbEvmSnapshot().Snapshots()
36 | }
37 |
--------------------------------------------------------------------------------
/gossip/evmstore/apply_genesis.go:
--------------------------------------------------------------------------------
1 | package evmstore
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/kvdb/batched"
5 | "github.com/syndtr/goleveldb/leveldb/opt"
6 |
7 | "github.com/Fantom-foundation/go-opera/opera/genesis"
8 | "github.com/Fantom-foundation/go-opera/utils/adapters/ethdb2kvdb"
9 | "github.com/Fantom-foundation/go-opera/utils/dbutil/autocompact"
10 | )
11 |
12 | // ApplyGenesis writes initial state.
13 | func (s *Store) ApplyGenesis(g genesis.Genesis) (err error) {
14 | db := batched.Wrap(autocompact.Wrap2M(ethdb2kvdb.Wrap(s.EvmDb), opt.GiB, 16*opt.GiB, true, "evm"))
15 | g.RawEvmItems.ForEach(func(key, value []byte) bool {
16 | err = db.Put(key, value)
17 | if err != nil {
18 | return false
19 | }
20 | return true
21 | })
22 | if err != nil {
23 | return err
24 | }
25 | return db.Write()
26 | }
27 |
28 | func (s *Store) WrapTablesAsBatched() (unwrap func()) {
29 | origTables := s.table
30 |
31 | batchedTxs := batched.Wrap(s.table.Txs)
32 | s.table.Txs = batchedTxs
33 |
34 | batchedTxPositions := batched.Wrap(s.table.TxPositions)
35 | s.table.TxPositions = batchedTxPositions
36 |
37 | unwrapLogs := s.EvmLogs.WrapTablesAsBatched()
38 |
39 | batchedReceipts := batched.Wrap(autocompact.Wrap2M(s.table.Receipts, opt.GiB, 16*opt.GiB, false, "receipts"))
40 | s.table.Receipts = batchedReceipts
41 | return func() {
42 | _ = batchedTxs.Flush()
43 | _ = batchedTxPositions.Flush()
44 | _ = batchedReceipts.Flush()
45 | unwrapLogs()
46 | s.table = origTables
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/gossip/evmstore/evmpruner/exact.go:
--------------------------------------------------------------------------------
1 | package evmpruner
2 |
3 | import (
4 | "errors"
5 | "io"
6 |
7 | "github.com/Fantom-foundation/lachesis-base/kvdb"
8 | "github.com/Fantom-foundation/lachesis-base/kvdb/leveldb"
9 | "github.com/ethereum/go-ethereum/common"
10 | "github.com/ethereum/go-ethereum/core/rawdb"
11 | "github.com/syndtr/goleveldb/leveldb/opt"
12 | )
13 |
14 | type exactSetStore struct {
15 | db kvdb.Store
16 | }
17 |
18 | func NewLevelDBSet(name string) (*exactSetStore, io.Closer, error) {
19 | db, err := leveldb.New(name, 256*opt.MiB, 0, nil, nil)
20 | if err != nil {
21 | return nil, nil, err
22 | }
23 | return &exactSetStore{db}, db, nil
24 | }
25 |
26 | func (set *exactSetStore) Put(key []byte, _ []byte) error {
27 | // If the key length is not 32bytes, ensure it's contract code
28 | // entry with new scheme.
29 | if len(key) != common.HashLength {
30 | isCode, codeKey := rawdb.IsCodeKey(key)
31 | if !isCode {
32 | return errors.New("invalid entry")
33 | }
34 | return set.db.Put(codeKey, []byte{})
35 | }
36 | return set.db.Put(key, []byte{})
37 | }
38 |
39 | func (set *exactSetStore) Delete(key []byte) error { panic("not supported") }
40 |
41 | func (set *exactSetStore) Contain(key []byte) (bool, error) {
42 | return set.db.Has(key)
43 | }
44 |
45 | func (set *exactSetStore) Commit(filename, tempname string) error {
46 | // No need in manual writing
47 | return nil
48 | }
49 |
--------------------------------------------------------------------------------
/gossip/evmstore/store_block_cache.go:
--------------------------------------------------------------------------------
1 | package evmstore
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
5 | "github.com/ethereum/go-ethereum/common"
6 |
7 | "github.com/Fantom-foundation/go-opera/evmcore"
8 | )
9 |
10 | func (s *Store) GetCachedEvmBlock(n idx.Block) *evmcore.EvmBlock {
11 | c, ok := s.cache.EvmBlocks.Get(n)
12 | if !ok {
13 | return nil
14 | }
15 |
16 | return c.(*evmcore.EvmBlock)
17 | }
18 |
19 | func (s *Store) SetCachedEvmBlock(n idx.Block, b *evmcore.EvmBlock) {
20 | var empty = common.Hash{}
21 | if b.EvmHeader.TxHash == empty {
22 | panic("You have to cache only completed blocks (with txs)")
23 | }
24 | s.cache.EvmBlocks.Add(n, b, uint(b.EstimateSize()))
25 | }
26 |
--------------------------------------------------------------------------------
/gossip/evmstore/store_test.go:
--------------------------------------------------------------------------------
1 | package evmstore
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/kvdb/memorydb"
5 | )
6 |
7 | func cachedStore() *Store {
8 | cfg := LiteStoreConfig()
9 |
10 | return NewStore(memorydb.NewProducer(""), cfg)
11 | }
12 |
13 | func nonCachedStore() *Store {
14 | cfg := StoreConfig{}
15 |
16 | return NewStore(memorydb.NewProducer(""), cfg)
17 | }
18 |
--------------------------------------------------------------------------------
/gossip/evmstore/store_tx.go:
--------------------------------------------------------------------------------
1 | package evmstore
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/hash"
5 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
6 | "github.com/ethereum/go-ethereum/common"
7 | "github.com/ethereum/go-ethereum/core/types"
8 | "github.com/ethereum/go-ethereum/log"
9 |
10 | "github.com/Fantom-foundation/go-opera/inter"
11 | )
12 |
13 | // SetTx stores non-event transaction.
14 | func (s *Store) SetTx(txid common.Hash, tx *types.Transaction) {
15 | s.rlp.Set(s.table.Txs, txid.Bytes(), tx)
16 | }
17 |
18 | // GetTx returns stored non-event transaction.
19 | func (s *Store) GetTx(txid common.Hash) *types.Transaction {
20 | tx, _ := s.rlp.Get(s.table.Txs, txid.Bytes(), &types.Transaction{}).(*types.Transaction)
21 |
22 | return tx
23 | }
24 |
25 | func (s *Store) GetBlockTxs(n idx.Block, block inter.Block, getEventPayload func(hash.Event) *inter.EventPayload) types.Transactions {
26 | if cached := s.GetCachedEvmBlock(n); cached != nil {
27 | return cached.Transactions
28 | }
29 |
30 | transactions := make(types.Transactions, 0, len(block.Txs)+len(block.InternalTxs)+len(block.Events)*10)
31 | for _, txid := range block.InternalTxs {
32 | tx := s.GetTx(txid)
33 | if tx == nil {
34 | log.Crit("Internal tx not found", "tx", txid.String())
35 | continue
36 | }
37 | transactions = append(transactions, tx)
38 | }
39 | for _, txid := range block.Txs {
40 | tx := s.GetTx(txid)
41 | if tx == nil {
42 | log.Crit("Tx not found", "tx", txid.String())
43 | continue
44 | }
45 | transactions = append(transactions, tx)
46 | }
47 | for _, id := range block.Events {
48 | e := getEventPayload(id)
49 | if e == nil {
50 | log.Crit("Block event not found", "event", id.String())
51 | continue
52 | }
53 | transactions = append(transactions, e.Txs()...)
54 | }
55 |
56 | transactions = inter.FilterSkippedTxs(transactions, block.SkippedTxs)
57 |
58 | return transactions
59 | }
60 |
--------------------------------------------------------------------------------
/gossip/evmstore/store_tx_position.go:
--------------------------------------------------------------------------------
1 | package evmstore
2 |
3 | /*
4 | In LRU cache data stored like pointer
5 | */
6 |
7 | import (
8 | "github.com/Fantom-foundation/lachesis-base/hash"
9 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
10 | "github.com/ethereum/go-ethereum/common"
11 | )
12 |
13 | type TxPosition struct {
14 | Block idx.Block
15 | Event hash.Event
16 | EventOffset uint32
17 | BlockOffset uint32
18 | }
19 |
20 | // SetTxPosition stores transaction block and position.
21 | func (s *Store) SetTxPosition(txid common.Hash, position TxPosition) {
22 | s.rlp.Set(s.table.TxPositions, txid.Bytes(), &position)
23 |
24 | // Add to LRU cache.
25 | s.cache.TxPositions.Add(txid.String(), &position, nominalSize)
26 | }
27 |
28 | // GetTxPosition returns stored transaction block and position.
29 | func (s *Store) GetTxPosition(txid common.Hash) *TxPosition {
30 | // Get data from LRU cache first.
31 | if c, ok := s.cache.TxPositions.Get(txid.String()); ok {
32 | if b, ok := c.(*TxPosition); ok {
33 | return b
34 | }
35 | }
36 |
37 | txPosition, _ := s.rlp.Get(s.table.TxPositions, txid.Bytes(), &TxPosition{}).(*TxPosition)
38 |
39 | // Add to LRU cache.
40 | if txPosition != nil {
41 | s.cache.TxPositions.Add(txid.String(), txPosition, nominalSize)
42 | }
43 |
44 | return txPosition
45 | }
46 |
--------------------------------------------------------------------------------
/gossip/proclogger/dag_logger.go:
--------------------------------------------------------------------------------
1 | package proclogger
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/Fantom-foundation/go-opera/inter"
7 | "github.com/Fantom-foundation/go-opera/logger"
8 | "github.com/Fantom-foundation/go-opera/utils"
9 | )
10 |
11 | func NewLogger() *Logger {
12 | return &Logger{
13 | Instance: logger.New(),
14 | }
15 | }
16 |
17 | // EventConnectionStarted starts the event logging
18 | // Not safe for concurrent use
19 | func (l *Logger) EventConnectionStarted(e inter.EventPayloadI, emitted bool) func() {
20 | l.dagSum.connected++
21 |
22 | start := time.Now()
23 | l.emitting = emitted
24 | l.noSummary = true // print summary after the whole event is processed
25 | l.lastID = e.ID()
26 | l.lastEventTime = e.CreationTime()
27 |
28 | return func() {
29 | now := time.Now()
30 | // logging for the individual item
31 | msg := "New event"
32 | logType := l.Log.Debug
33 | if emitted {
34 | msg = "New event emitted"
35 | logType = l.Log.Info
36 | }
37 | logType(msg, "id", e.ID(), "parents", len(e.Parents()), "by", e.Creator(),
38 | "frame", e.Frame(), "txs", e.Txs().Len(),
39 | "age", utils.PrettyDuration(now.Sub(e.CreationTime().Time())), "t", utils.PrettyDuration(now.Sub(start)))
40 | // logging for the summary
41 | l.dagSum.totalProcessing += now.Sub(start)
42 | l.emitting = false
43 | l.noSummary = false
44 | l.summary(now)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/gossip/protocols/blockrecords/brprocessor/config.go:
--------------------------------------------------------------------------------
1 | package brprocessor
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/syndtr/goleveldb/leveldb/opt"
7 |
8 | "github.com/Fantom-foundation/lachesis-base/inter/dag"
9 | "github.com/Fantom-foundation/lachesis-base/utils/cachescale"
10 | )
11 |
12 | type Config struct {
13 | BufferLimit dag.Metric
14 |
15 | SemaphoreTimeout time.Duration
16 |
17 | MaxTasks int
18 | }
19 |
20 | func DefaultConfig(scale cachescale.Func) Config {
21 | return Config{
22 | BufferLimit: dag.Metric{
23 | Num: 10000,
24 | Size: scale.U64(15 * opt.MiB),
25 | },
26 | SemaphoreTimeout: 10 * time.Second,
27 | MaxTasks: 512,
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/gossip/protocols/blockrecords/brstream/brstreamleecher/config.go:
--------------------------------------------------------------------------------
1 | package brstreamleecher
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/gossip/basestream/basestreamleecher/basepeerleecher"
7 | )
8 |
9 | type Config struct {
10 | Session basepeerleecher.EpochDownloaderConfig
11 | RecheckInterval time.Duration
12 | BaseProgressWatchdog time.Duration
13 | BaseSessionWatchdog time.Duration
14 | MinSessionRestart time.Duration
15 | MaxSessionRestart time.Duration
16 | }
17 |
18 | // DefaultConfig returns default leecher config
19 | func DefaultConfig() Config {
20 | return Config{
21 | Session: basepeerleecher.EpochDownloaderConfig{
22 | DefaultChunkItemsNum: 500,
23 | DefaultChunkItemsSize: 512 * 1024,
24 | ParallelChunksDownload: 6,
25 | RecheckInterval: 10 * time.Millisecond,
26 | },
27 | RecheckInterval: time.Second,
28 | BaseProgressWatchdog: time.Second * 5,
29 | BaseSessionWatchdog: time.Second * 30 * 5,
30 | MinSessionRestart: time.Second * 5,
31 | MaxSessionRestart: time.Minute * 5,
32 | }
33 | }
34 |
35 | // LiteConfig returns default leecher config for tests
36 | func LiteConfig() Config {
37 | cfg := DefaultConfig()
38 | cfg.Session.DefaultChunkItemsSize /= 10
39 | cfg.Session.DefaultChunkItemsNum /= 10
40 | cfg.Session.ParallelChunksDownload = cfg.Session.ParallelChunksDownload/2 + 1
41 | return cfg
42 | }
43 |
--------------------------------------------------------------------------------
/gossip/protocols/blockrecords/brstream/brstreamseeder/config.go:
--------------------------------------------------------------------------------
1 | package brstreamseeder
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/gossip/basestream/basestreamseeder"
5 | "github.com/Fantom-foundation/lachesis-base/utils/cachescale"
6 | )
7 |
8 | type Config basestreamseeder.Config
9 |
10 | func DefaultConfig(scale cachescale.Func) Config {
11 | return Config{
12 | SenderThreads: 2,
13 | MaxSenderTasks: 64,
14 | MaxPendingResponsesSize: scale.I64(32 * 1024 * 1024),
15 | MaxResponsePayloadNum: 4096,
16 | MaxResponsePayloadSize: 8 * 1024 * 1024,
17 | MaxResponseChunks: 12,
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gossip/protocols/blockrecords/brstream/types.go:
--------------------------------------------------------------------------------
1 | package brstream
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
7 | "github.com/ethereum/go-ethereum/rlp"
8 |
9 | "github.com/Fantom-foundation/lachesis-base/gossip/basestream"
10 | )
11 |
12 | type Request struct {
13 | Session Session
14 | Limit Metric
15 | Type basestream.RequestType
16 | MaxChunks uint32
17 | }
18 |
19 | type Response struct {
20 | SessionID uint32
21 | Done bool
22 | Payload []rlp.RawValue
23 | }
24 |
25 | type Session struct {
26 | ID uint32
27 | Start Locator
28 | Stop Locator
29 | }
30 |
31 | type Locator idx.Block
32 |
33 | func (l Locator) Compare(b basestream.Locator) int {
34 | if l == b.(Locator) {
35 | return 0
36 | }
37 | if l < b.(Locator) {
38 | return -1
39 | }
40 | return 1
41 | }
42 |
43 | func (l Locator) Inc() basestream.Locator {
44 | return l + 1
45 | }
46 |
47 | type Payload struct {
48 | Items []rlp.RawValue
49 | Keys []Locator
50 | Size uint64
51 | }
52 |
53 | func (p *Payload) AddFullBlockRecords(id Locator, brsB rlp.RawValue) {
54 | p.Items = append(p.Items, brsB)
55 | p.Keys = append(p.Keys, id)
56 | p.Size += uint64(len(brsB))
57 | }
58 |
59 | func (p Payload) Len() int {
60 | return len(p.Keys)
61 | }
62 |
63 | func (p Payload) TotalSize() uint64 {
64 | return p.Size
65 | }
66 |
67 | func (p Payload) TotalMemSize() int {
68 | return int(p.Size) + len(p.Keys)*32
69 | }
70 |
71 | type Metric struct {
72 | Num idx.Block
73 | Size uint64
74 | }
75 |
76 | func (m Metric) String() string {
77 | return fmt.Sprintf("{Num=%d,Size=%d}", m.Num, m.Size)
78 | }
79 |
--------------------------------------------------------------------------------
/gossip/protocols/blockvotes/bvprocessor/config.go:
--------------------------------------------------------------------------------
1 | package bvprocessor
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/syndtr/goleveldb/leveldb/opt"
7 |
8 | "github.com/Fantom-foundation/lachesis-base/inter/dag"
9 | "github.com/Fantom-foundation/lachesis-base/utils/cachescale"
10 | )
11 |
12 | type Config struct {
13 | BufferLimit dag.Metric
14 |
15 | SemaphoreTimeout time.Duration
16 |
17 | MaxTasks int
18 | }
19 |
20 | func DefaultConfig(scale cachescale.Func) Config {
21 | return Config{
22 | BufferLimit: dag.Metric{
23 | Num: 3000,
24 | Size: scale.U64(15 * opt.MiB),
25 | },
26 | SemaphoreTimeout: 10 * time.Second,
27 | MaxTasks: 512,
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/gossip/protocols/blockvotes/bvstream/bvstreamleecher/config.go:
--------------------------------------------------------------------------------
1 | package bvstreamleecher
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/gossip/basestream/basestreamleecher/basepeerleecher"
7 | )
8 |
9 | type Config struct {
10 | Session basepeerleecher.EpochDownloaderConfig
11 | RecheckInterval time.Duration
12 | BaseProgressWatchdog time.Duration
13 | BaseSessionWatchdog time.Duration
14 | MinSessionRestart time.Duration
15 | MaxSessionRestart time.Duration
16 | }
17 |
18 | // DefaultConfig returns default leecher config
19 | func DefaultConfig() Config {
20 | return Config{
21 | Session: basepeerleecher.EpochDownloaderConfig{
22 | DefaultChunkItemsNum: 500,
23 | DefaultChunkItemsSize: 512 * 1024,
24 | ParallelChunksDownload: 6,
25 | RecheckInterval: 10 * time.Millisecond,
26 | },
27 | RecheckInterval: time.Second,
28 | BaseProgressWatchdog: time.Second * 5,
29 | BaseSessionWatchdog: time.Second * 30 * 5,
30 | MinSessionRestart: time.Second * 5,
31 | MaxSessionRestart: time.Minute * 5,
32 | }
33 | }
34 |
35 | // LiteConfig returns default leecher config for tests
36 | func LiteConfig() Config {
37 | cfg := DefaultConfig()
38 | cfg.Session.DefaultChunkItemsSize /= 10
39 | cfg.Session.DefaultChunkItemsNum /= 10
40 | cfg.Session.ParallelChunksDownload = cfg.Session.ParallelChunksDownload/2 + 1
41 | return cfg
42 | }
43 |
--------------------------------------------------------------------------------
/gossip/protocols/blockvotes/bvstream/bvstreamseeder/config.go:
--------------------------------------------------------------------------------
1 | package bvstreamseeder
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/gossip/basestream/basestreamseeder"
5 | "github.com/Fantom-foundation/lachesis-base/utils/cachescale"
6 | )
7 |
8 | type Config basestreamseeder.Config
9 |
10 | func DefaultConfig(scale cachescale.Func) Config {
11 | return Config{
12 | SenderThreads: 2,
13 | MaxSenderTasks: 64,
14 | MaxPendingResponsesSize: scale.I64(32 * 1024 * 1024),
15 | MaxResponsePayloadNum: 4096,
16 | MaxResponsePayloadSize: 8 * 1024 * 1024,
17 | MaxResponseChunks: 12,
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gossip/protocols/blockvotes/bvstream/types.go:
--------------------------------------------------------------------------------
1 | package bvstream
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "math/big"
7 |
8 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
9 | "github.com/ethereum/go-ethereum/common"
10 | "github.com/ethereum/go-ethereum/rlp"
11 |
12 | "github.com/Fantom-foundation/lachesis-base/gossip/basestream"
13 | )
14 |
15 | type Request struct {
16 | Session Session
17 | Limit Metric
18 | Type basestream.RequestType
19 | MaxChunks uint32
20 | }
21 |
22 | type Response struct {
23 | SessionID uint32
24 | Done bool
25 | Payload []rlp.RawValue
26 | }
27 |
28 | type Session struct {
29 | ID uint32
30 | Start Locator
31 | Stop Locator
32 | }
33 |
34 | type Locator []byte
35 |
36 | func (l Locator) Compare(b basestream.Locator) int {
37 | return bytes.Compare(l, b.(Locator))
38 | }
39 |
40 | func (l Locator) Inc() basestream.Locator {
41 | nextBn := new(big.Int).SetBytes(l)
42 | nextBn.Add(nextBn, common.Big1)
43 | return Locator(common.LeftPadBytes(nextBn.Bytes(), len(l)))
44 | }
45 |
46 | type Payload struct {
47 | Items []rlp.RawValue
48 | Keys []Locator
49 | Size uint64
50 | }
51 |
52 | func (p *Payload) AddSignedBlockVotes(id Locator, bvsB rlp.RawValue) {
53 | p.Items = append(p.Items, bvsB)
54 | p.Keys = append(p.Keys, id)
55 | p.Size += uint64(len(bvsB))
56 | }
57 |
58 | func (p Payload) Len() int {
59 | return len(p.Keys)
60 | }
61 |
62 | func (p Payload) TotalSize() uint64 {
63 | return p.Size
64 | }
65 |
66 | func (p Payload) TotalMemSize() int {
67 | return int(p.Size) + len(p.Keys)*128
68 | }
69 |
70 | type Metric struct {
71 | Num idx.Block
72 | Size uint64
73 | }
74 |
75 | func (m Metric) String() string {
76 | return fmt.Sprintf("{Num=%d,Size=%d}", m.Num, m.Size)
77 | }
78 |
--------------------------------------------------------------------------------
/gossip/protocols/dag/dagstream/dagstreamleecher/config.go:
--------------------------------------------------------------------------------
1 | package dagstreamleecher
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/gossip/basestream/basestreamleecher/basepeerleecher"
7 | )
8 |
9 | type Config struct {
10 | Session basepeerleecher.EpochDownloaderConfig
11 | RecheckInterval time.Duration
12 | BaseProgressWatchdog time.Duration
13 | BaseSessionWatchdog time.Duration
14 | MinSessionRestart time.Duration
15 | MaxSessionRestart time.Duration
16 | }
17 |
18 | // DefaultConfig returns default leecher config
19 | func DefaultConfig() Config {
20 | return Config{
21 | Session: basepeerleecher.EpochDownloaderConfig{
22 | DefaultChunkItemsNum: 500,
23 | DefaultChunkItemsSize: 512 * 1024,
24 | ParallelChunksDownload: 6,
25 | RecheckInterval: 10 * time.Millisecond,
26 | },
27 | RecheckInterval: time.Second,
28 | BaseProgressWatchdog: time.Second * 5,
29 | BaseSessionWatchdog: time.Second * 30 * 5,
30 | MinSessionRestart: time.Second * 5,
31 | MaxSessionRestart: time.Minute * 5,
32 | }
33 | }
34 |
35 | // LiteConfig returns default leecher config for tests
36 | func LiteConfig() Config {
37 | cfg := DefaultConfig()
38 | cfg.Session.DefaultChunkItemsSize /= 10
39 | cfg.Session.DefaultChunkItemsNum /= 10
40 | cfg.Session.ParallelChunksDownload = cfg.Session.ParallelChunksDownload/2 + 1
41 | return cfg
42 | }
43 |
--------------------------------------------------------------------------------
/gossip/protocols/dag/dagstream/dagstreamseeder/config.go:
--------------------------------------------------------------------------------
1 | package dagstreamseeder
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/gossip/basestream/basestreamseeder"
5 | "github.com/Fantom-foundation/lachesis-base/utils/cachescale"
6 | )
7 |
8 | type Config basestreamseeder.Config
9 |
10 | func DefaultConfig(scale cachescale.Func) Config {
11 | return Config{
12 | SenderThreads: 8,
13 | MaxSenderTasks: 128,
14 | MaxPendingResponsesSize: scale.I64(64 * 1024 * 1024),
15 | MaxResponsePayloadNum: 16384,
16 | MaxResponsePayloadSize: 8 * 1024 * 1024,
17 | MaxResponseChunks: 12,
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gossip/protocols/dag/dagstream/types.go:
--------------------------------------------------------------------------------
1 | package dagstream
2 |
3 | import (
4 | "bytes"
5 | "math/big"
6 |
7 | "github.com/ethereum/go-ethereum/common"
8 | "github.com/ethereum/go-ethereum/rlp"
9 |
10 | "github.com/Fantom-foundation/lachesis-base/gossip/basestream"
11 | "github.com/Fantom-foundation/lachesis-base/hash"
12 | "github.com/Fantom-foundation/lachesis-base/inter/dag"
13 | )
14 |
15 | type Request struct {
16 | Session Session
17 | Limit dag.Metric
18 | Type basestream.RequestType
19 | MaxChunks uint32
20 | }
21 |
22 | type Response struct {
23 | SessionID uint32
24 | Done bool
25 | IDs hash.Events
26 | Events []rlp.RawValue
27 | }
28 |
29 | type Session struct {
30 | ID uint32
31 | Start Locator
32 | Stop Locator
33 | }
34 |
35 | type Locator []byte
36 |
37 | func (l Locator) Compare(b basestream.Locator) int {
38 | return bytes.Compare(l, b.(Locator))
39 | }
40 |
41 | func (l Locator) Inc() basestream.Locator {
42 | nextBn := new(big.Int).SetBytes(l)
43 | nextBn.Add(nextBn, common.Big1)
44 | return Locator(common.LeftPadBytes(nextBn.Bytes(), len(l)))
45 | }
46 |
47 | type Payload struct {
48 | IDs hash.Events
49 | Events []rlp.RawValue
50 | Size uint64
51 | }
52 |
53 | func (p *Payload) AddEvent(id hash.Event, eventB rlp.RawValue) {
54 | p.IDs = append(p.IDs, id)
55 | p.Events = append(p.Events, eventB)
56 | p.Size += uint64(len(eventB))
57 | }
58 |
59 | func (p *Payload) AddID(id hash.Event, size int) {
60 | p.IDs = append(p.IDs, id)
61 | p.Size += uint64(size)
62 | }
63 |
64 | func (p Payload) Len() int {
65 | return len(p.IDs)
66 | }
67 |
68 | func (p Payload) TotalSize() uint64 {
69 | return p.Size
70 | }
71 |
72 | func (p Payload) TotalMemSize() int {
73 | if len(p.Events) != 0 {
74 | return int(p.Size) + len(p.IDs)*128
75 | }
76 | return len(p.IDs) * 128
77 | }
78 |
79 | const (
80 | RequestIDs basestream.RequestType = 0
81 | RequestEvents basestream.RequestType = 2
82 | )
83 |
--------------------------------------------------------------------------------
/gossip/protocols/epochpacks/epprocessor/config.go:
--------------------------------------------------------------------------------
1 | package epprocessor
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/syndtr/goleveldb/leveldb/opt"
7 |
8 | "github.com/Fantom-foundation/lachesis-base/inter/dag"
9 | "github.com/Fantom-foundation/lachesis-base/utils/cachescale"
10 | )
11 |
12 | type Config struct {
13 | BufferLimit dag.Metric
14 |
15 | SemaphoreTimeout time.Duration
16 |
17 | MaxTasks int
18 | }
19 |
20 | func DefaultConfig(scale cachescale.Func) Config {
21 | return Config{
22 | BufferLimit: dag.Metric{
23 | Num: 10000,
24 | Size: scale.U64(15 * opt.MiB),
25 | },
26 | SemaphoreTimeout: 10 * time.Second,
27 | MaxTasks: 512,
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/gossip/protocols/epochpacks/epstream/epstreamleecher/config.go:
--------------------------------------------------------------------------------
1 | package epstreamleecher
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/gossip/basestream/basestreamleecher/basepeerleecher"
7 | )
8 |
9 | type Config struct {
10 | Session basepeerleecher.EpochDownloaderConfig
11 | RecheckInterval time.Duration
12 | BaseProgressWatchdog time.Duration
13 | BaseSessionWatchdog time.Duration
14 | MinSessionRestart time.Duration
15 | MaxSessionRestart time.Duration
16 | }
17 |
18 | // DefaultConfig returns default leecher config
19 | func DefaultConfig() Config {
20 | return Config{
21 | Session: basepeerleecher.EpochDownloaderConfig{
22 | DefaultChunkItemsNum: 500,
23 | DefaultChunkItemsSize: 512 * 1024,
24 | ParallelChunksDownload: 6,
25 | RecheckInterval: 10 * time.Millisecond,
26 | },
27 | RecheckInterval: time.Second,
28 | BaseProgressWatchdog: time.Second * 5,
29 | BaseSessionWatchdog: time.Second * 30 * 5,
30 | MinSessionRestart: time.Second * 5,
31 | MaxSessionRestart: time.Minute * 5,
32 | }
33 | }
34 |
35 | // LiteConfig returns default leecher config for tests
36 | func LiteConfig() Config {
37 | cfg := DefaultConfig()
38 | cfg.Session.DefaultChunkItemsSize /= 10
39 | cfg.Session.DefaultChunkItemsNum /= 10
40 | cfg.Session.ParallelChunksDownload = cfg.Session.ParallelChunksDownload/2 + 1
41 | return cfg
42 | }
43 |
--------------------------------------------------------------------------------
/gossip/protocols/epochpacks/epstream/epstreamseeder/config.go:
--------------------------------------------------------------------------------
1 | package epstreamseeder
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/gossip/basestream/basestreamseeder"
5 | "github.com/Fantom-foundation/lachesis-base/utils/cachescale"
6 | )
7 |
8 | type Config basestreamseeder.Config
9 |
10 | func DefaultConfig(scale cachescale.Func) Config {
11 | return Config{
12 | SenderThreads: 2,
13 | MaxSenderTasks: 64,
14 | MaxPendingResponsesSize: scale.I64(32 * 1024 * 1024),
15 | MaxResponsePayloadNum: 4096,
16 | MaxResponsePayloadSize: 8 * 1024 * 1024,
17 | MaxResponseChunks: 12,
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gossip/protocols/epochpacks/epstream/types.go:
--------------------------------------------------------------------------------
1 | package epstream
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
7 | "github.com/ethereum/go-ethereum/rlp"
8 |
9 | "github.com/Fantom-foundation/lachesis-base/gossip/basestream"
10 | )
11 |
12 | type Request struct {
13 | Session Session
14 | Limit Metric
15 | Type basestream.RequestType
16 | MaxChunks uint32
17 | }
18 |
19 | type Response struct {
20 | SessionID uint32
21 | Done bool
22 | Payload []rlp.RawValue
23 | }
24 |
25 | type Session struct {
26 | ID uint32
27 | Start Locator
28 | Stop Locator
29 | }
30 |
31 | type Locator idx.Epoch
32 |
33 | func (l Locator) Compare(b basestream.Locator) int {
34 | if l == b.(Locator) {
35 | return 0
36 | }
37 | if l < b.(Locator) {
38 | return -1
39 | }
40 | return 1
41 | }
42 |
43 | func (l Locator) Inc() basestream.Locator {
44 | return l + 1
45 | }
46 |
47 | type Payload struct {
48 | Items []rlp.RawValue
49 | Keys []Locator
50 | Size uint64
51 | }
52 |
53 | func (p *Payload) AddEpochPacks(id Locator, epsB rlp.RawValue) {
54 | p.Items = append(p.Items, epsB)
55 | p.Keys = append(p.Keys, id)
56 | p.Size += uint64(len(epsB))
57 | }
58 |
59 | func (p Payload) Len() int {
60 | return len(p.Keys)
61 | }
62 |
63 | func (p Payload) TotalSize() uint64 {
64 | return p.Size
65 | }
66 |
67 | func (p Payload) TotalMemSize() int {
68 | return int(p.Size) + len(p.Keys)*32
69 | }
70 |
71 | type Metric struct {
72 | Num idx.Epoch
73 | Size uint64
74 | }
75 |
76 | func (m Metric) String() string {
77 | return fmt.Sprintf("{Num=%d,Size=%d}", m.Num, m.Size)
78 | }
79 |
--------------------------------------------------------------------------------
/gossip/protocols/snap/events.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The go-ethereum Authors
2 | // This file is part of the go-ethereum library.
3 | //
4 | // The go-ethereum library is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // The go-ethereum library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU Lesser General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with the go-ethereum library. If not, see .
16 |
17 | package snap
18 |
19 | import "github.com/ethereum/go-ethereum/core/types"
20 |
21 | type DoneEvent struct {
22 | Latest *types.Header
23 | }
24 | type StartEvent struct{}
25 | type FailedEvent struct{ Err error }
26 |
--------------------------------------------------------------------------------
/gossip/protocols/snap/snapstream/snapleecher/types.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The go-ethereum Authors
2 | // This file is part of the go-ethereum library.
3 | //
4 | // The go-ethereum library is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // The go-ethereum library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU Lesser General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with the go-ethereum library. If not, see .
16 |
17 | package snapleecher
18 |
19 | import (
20 | "fmt"
21 | )
22 |
23 | // peerDropFn is a callback type for dropping a peer detected as malicious.
24 | type peerDropFn func(id string)
25 |
26 | // dataPack is a data message returned by a peer for some query.
27 | type dataPack interface {
28 | PeerId() string
29 | Items() int
30 | Stats() string
31 | }
32 |
33 | // statePack is a batch of states returned by a peer.
34 | type statePack struct {
35 | peerID string
36 | states [][]byte
37 | }
38 |
39 | func (p *statePack) PeerId() string { return p.peerID }
40 | func (p *statePack) Items() int { return len(p.states) }
41 | func (p *statePack) Stats() string { return fmt.Sprintf("%d", len(p.states)) }
42 |
--------------------------------------------------------------------------------
/gossip/store_activation_heights.go:
--------------------------------------------------------------------------------
1 | package gossip
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/opera"
5 | )
6 |
7 | func (s *Store) AddUpgradeHeight(h opera.UpgradeHeight) {
8 | orig := s.GetUpgradeHeights()
9 | // allocate new memory to avoid race condition in cache
10 | cp := make([]opera.UpgradeHeight, 0, len(orig)+1)
11 | cp = append(append(cp, orig...), h)
12 |
13 | s.rlp.Set(s.table.UpgradeHeights, []byte{}, cp)
14 | s.cache.UpgradeHeights.Store(cp)
15 | }
16 |
17 | func (s *Store) GetUpgradeHeights() []opera.UpgradeHeight {
18 | if v := s.cache.UpgradeHeights.Load(); v != nil {
19 | return v.([]opera.UpgradeHeight)
20 | }
21 | hh, ok := s.rlp.Get(s.table.UpgradeHeights, []byte{}, &[]opera.UpgradeHeight{}).(*[]opera.UpgradeHeight)
22 | if !ok {
23 | return []opera.UpgradeHeight{}
24 | }
25 | s.cache.UpgradeHeights.Store(*hh)
26 | return *hh
27 | }
28 |
--------------------------------------------------------------------------------
/gossip/store_llr_state.go:
--------------------------------------------------------------------------------
1 | package gossip
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
5 | "github.com/ethereum/go-ethereum/log"
6 | )
7 |
8 | type LlrState struct {
9 | LowestEpochToDecide idx.Epoch
10 | LowestEpochToFill idx.Epoch
11 |
12 | LowestBlockToDecide idx.Block
13 | LowestBlockToFill idx.Block
14 | }
15 |
16 | func (s *Store) setLlrState(llrs LlrState) {
17 | s.cache.LlrState.Store(&llrs)
18 | }
19 |
20 | func (s *Store) ModifyLlrState(f func(*LlrState)) {
21 | s.mutex.WriteLlrState.Lock()
22 | defer s.mutex.WriteLlrState.Unlock()
23 | llrs := s.GetLlrState()
24 | f(&llrs)
25 | s.setLlrState(llrs)
26 | }
27 |
28 | func (s *Store) GetLlrState() LlrState {
29 | if v := s.cache.LlrState.Load(); v != nil {
30 | return *v.(*LlrState)
31 | }
32 | v, ok := s.rlp.Get(s.table.LlrState, []byte{}, &LlrState{}).(*LlrState)
33 | if !ok {
34 | log.Crit("LLR state reading failed: genesis not applied")
35 | }
36 | s.cache.LlrState.Store(v)
37 | return *v
38 | }
39 |
40 | // FlushLlrState stores the LLR state in DB
41 | func (s *Store) FlushLlrState() {
42 | s.rlp.Set(s.table.LlrState, []byte{}, s.GetLlrState())
43 | }
44 |
--------------------------------------------------------------------------------
/gossip/tflusher.go:
--------------------------------------------------------------------------------
1 | package gossip
2 |
3 | import (
4 | "sync"
5 | "time"
6 | )
7 |
8 | type PeriodicFlusherCallaback struct {
9 | busy func() bool
10 | commitNeeded func() bool
11 | commit func()
12 | }
13 |
14 | // PeriodicFlusher periodically commits the Store if isCommitNeeded returns true
15 | type PeriodicFlusher struct {
16 | period time.Duration
17 | callback PeriodicFlusherCallaback
18 |
19 | wg sync.WaitGroup
20 | quit chan struct{}
21 | }
22 |
23 | func (c *PeriodicFlusher) loop() {
24 | defer c.wg.Done()
25 | ticker := time.NewTicker(c.period)
26 | defer ticker.Stop()
27 | for {
28 | select {
29 | case <-ticker.C:
30 | if !c.callback.busy() && c.callback.commitNeeded() {
31 | c.callback.commit()
32 | }
33 | case <-c.quit:
34 | return
35 | }
36 | }
37 | }
38 |
39 | func (c *PeriodicFlusher) Start() {
40 | c.wg.Add(1)
41 | go c.loop()
42 | }
43 |
44 | func (c *PeriodicFlusher) Stop() {
45 | close(c.quit)
46 | c.wg.Wait()
47 | }
48 |
--------------------------------------------------------------------------------
/integration/diskusage.go:
--------------------------------------------------------------------------------
1 | // Copyright 2021 The go-ethereum Authors
2 | // This file is part of the go-ethereum library.
3 | //
4 | // The go-ethereum library is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // The go-ethereum library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU Lesser General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with the go-ethereum library. If not, see .
16 |
17 | //go:build !windows && !openbsd
18 | // +build !windows,!openbsd
19 |
20 | package integration
21 |
22 | import (
23 | "fmt"
24 |
25 | "golang.org/x/sys/unix"
26 | )
27 |
28 | func getFreeDiskSpace(path string) (uint64, error) {
29 | var stat unix.Statfs_t
30 | if err := unix.Statfs(path, &stat); err != nil {
31 | return 0, fmt.Errorf("failed to call Statfs: %v", err)
32 | }
33 |
34 | // Available blocks * size per block = available space in bytes
35 | var bavail = stat.Bavail
36 | if stat.Bavail < 0 {
37 | // FreeBSD can have a negative number of blocks available
38 | // because of the grace limit.
39 | bavail = 0
40 | }
41 | //nolint:unconvert
42 | return uint64(bavail) * uint64(stat.Bsize), nil
43 | }
44 |
--------------------------------------------------------------------------------
/integration/diskusage_openbsd.go:
--------------------------------------------------------------------------------
1 | // Copyright 2021 The go-ethereum Authors
2 | // This file is part of the go-ethereum library.
3 | //
4 | // The go-ethereum library is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // The go-ethereum library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU Lesser General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with the go-ethereum library. If not, see .
16 |
17 | //go:build openbsd
18 | // +build openbsd
19 |
20 | package integration
21 |
22 | import (
23 | "fmt"
24 |
25 | "golang.org/x/sys/unix"
26 | )
27 |
28 | func getFreeDiskSpace(path string) (uint64, error) {
29 | var stat unix.Statfs_t
30 | if err := unix.Statfs(path, &stat); err != nil {
31 | return 0, fmt.Errorf("failed to call Statfs: %v", err)
32 | }
33 |
34 | // Available blocks * size per block = available space in bytes
35 | var bavail = stat.F_bavail
36 | // Not sure if the following check is necessary for OpenBSD
37 | if stat.F_bavail < 0 {
38 | // FreeBSD can have a negative number of blocks available
39 | // because of the grace limit.
40 | bavail = 0
41 | }
42 | //nolint:unconvert
43 | return uint64(bavail) * uint64(stat.F_bsize), nil
44 | }
45 |
--------------------------------------------------------------------------------
/integration/diskusage_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright 2021 The go-ethereum Authors
2 | // This file is part of the go-ethereum library.
3 | //
4 | // The go-ethereum library is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU Lesser General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // The go-ethereum library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU Lesser General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU Lesser General Public License
15 | // along with the go-ethereum library. If not, see .
16 |
17 | package integration
18 |
19 | import (
20 | "fmt"
21 |
22 | "golang.org/x/sys/windows"
23 | )
24 |
25 | func getFreeDiskSpace(path string) (uint64, error) {
26 |
27 | cwd, err := windows.UTF16PtrFromString(path)
28 | if err != nil {
29 | return 0, fmt.Errorf("failed to call UTF16PtrFromString: %v", err)
30 | }
31 |
32 | var freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes uint64
33 | if err := windows.GetDiskFreeSpaceEx(cwd, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes); err != nil {
34 | return 0, fmt.Errorf("failed to call GetDiskFreeSpaceEx: %v", err)
35 | }
36 |
37 | return freeBytesAvailableToCaller, nil
38 | }
39 |
--------------------------------------------------------------------------------
/integration/metric_test.go:
--------------------------------------------------------------------------------
1 | package integration
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestGenericNameOfTmpDB(t *testing.T) {
10 | require := require.New(t)
11 |
12 | for name, exp := range map[string]string{
13 | "": "",
14 | "main": "main",
15 | "main-single": "main-single",
16 | "lachesis-0": "lachesis-tmp",
17 | "lachesis-0999": "lachesis-tmp",
18 | "gossip-50": "gossip-tmp",
19 | "epoch-1": "epoch-tmp",
20 | "xxx-1a": "xxx-1a",
21 | "123": "123",
22 | } {
23 | got := genericNameOfTmpDB(name)
24 | require.Equal(exp, got, name)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/integration/status.go:
--------------------------------------------------------------------------------
1 | package integration
2 |
3 | import (
4 | "os"
5 | "path"
6 |
7 | "github.com/Fantom-foundation/go-opera/utils"
8 | )
9 |
10 | func isInterrupted(chaindataDir string) bool {
11 | return utils.FileExists(path.Join(chaindataDir, "unfinished"))
12 | }
13 |
14 | func setGenesisProcessing(chaindataDir string) {
15 | f, _ := os.Create(path.Join(chaindataDir, "unfinished"))
16 | if f != nil {
17 | _ = f.Close()
18 | }
19 | }
20 |
21 | func setGenesisComplete(chaindataDir string) {
22 | _ = os.Remove(path.Join(chaindataDir, "unfinished"))
23 | }
24 |
--------------------------------------------------------------------------------
/integration/xenblocks/reporter/stack.go:
--------------------------------------------------------------------------------
1 | package reporter
2 |
3 | import (
4 | "sync"
5 | )
6 |
7 | type SingleStack struct {
8 | lock sync.Mutex
9 | job *WebSocketJob
10 | }
11 |
12 | func NewSingleStack() *SingleStack {
13 | return &SingleStack{sync.Mutex{}, nil}
14 | }
15 |
16 | func (s *SingleStack) Push(v *WebSocketJob) {
17 | s.lock.Lock()
18 | defer s.lock.Unlock()
19 |
20 | s.job = v
21 | }
22 |
23 | func (s *SingleStack) Pop() *WebSocketJob {
24 | s.lock.Lock()
25 | defer s.lock.Unlock()
26 |
27 | v := s.job
28 | s.job = nil
29 | return v
30 | }
31 |
--------------------------------------------------------------------------------
/inter/block.go:
--------------------------------------------------------------------------------
1 | package inter
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/hash"
5 | "github.com/ethereum/go-ethereum/common"
6 | "github.com/ethereum/go-ethereum/core/types"
7 | )
8 |
9 | type Block struct {
10 | Time Timestamp
11 | Atropos hash.Event
12 | Events hash.Events
13 | Txs []common.Hash // non event txs (received via genesis or LLR)
14 | InternalTxs []common.Hash // DEPRECATED in favor of using only Txs fields and method internal.IsInternal
15 | SkippedTxs []uint32 // indexes of skipped txs, starting from first tx of first event, ending with last tx of last event
16 | GasUsed uint64
17 | Root hash.Hash
18 | }
19 |
20 | func (b *Block) EstimateSize() int {
21 | return (len(b.Events)+len(b.InternalTxs)+len(b.Txs)+1+1)*32 + len(b.SkippedTxs)*4 + 8 + 8
22 | }
23 |
24 | func FilterSkippedTxs(txs types.Transactions, skippedTxs []uint32) types.Transactions {
25 | if len(skippedTxs) == 0 {
26 | // short circuit if nothing to skip
27 | return txs
28 | }
29 | skipCount := 0
30 | filteredTxs := make(types.Transactions, 0, len(txs))
31 | for i, tx := range txs {
32 | if skipCount < len(skippedTxs) && skippedTxs[skipCount] == uint32(i) {
33 | skipCount++
34 | } else {
35 | filteredTxs = append(filteredTxs, tx)
36 | }
37 | }
38 |
39 | return filteredTxs
40 | }
41 |
--------------------------------------------------------------------------------
/inter/drivertype/driver_type.go:
--------------------------------------------------------------------------------
1 | package drivertype
2 |
3 | import (
4 | "math/big"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
7 |
8 | "github.com/Fantom-foundation/go-opera/inter/validatorpk"
9 | )
10 |
11 | var (
12 | // DoublesignBit is set if validator has a confirmed pair of fork events
13 | DoublesignBit = uint64(1 << 7)
14 | OkStatus = uint64(0)
15 | )
16 |
17 | // Validator is the node-side representation of Driver validator
18 | type Validator struct {
19 | Weight *big.Int
20 | PubKey validatorpk.PubKey
21 | }
22 |
23 | // ValidatorAndID is pair Validator + ValidatorID
24 | type ValidatorAndID struct {
25 | ValidatorID idx.ValidatorID
26 | Validator Validator
27 | }
28 |
--------------------------------------------------------------------------------
/inter/event_test.go:
--------------------------------------------------------------------------------
1 | package inter
2 |
3 | import (
4 | "encoding/hex"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestCalcMisbehaviourProofsHash(t *testing.T) {
11 | v := []MisbehaviourProof{
12 | MisbehaviourProof{
13 | EventsDoublesign: &EventsDoublesign{
14 | Pair: [2]SignedEventLocator{
15 | test_signed_event_locator,
16 | test_signed_event_locator,
17 | },
18 | },
19 | },
20 | MisbehaviourProof{
21 | BlockVoteDoublesign: &BlockVoteDoublesign{
22 | Block: test_block_votes.Start,
23 | Pair: [2]LlrSignedBlockVotes{
24 | test_llr_signed_block_votes,
25 | test_llr_signed_block_votes,
26 | },
27 | },
28 | },
29 | MisbehaviourProof{
30 | WrongBlockVote: &WrongBlockVote{
31 | Block: test_block_votes.Start,
32 | Pals: [2]LlrSignedBlockVotes{
33 | test_llr_signed_block_votes,
34 | test_llr_signed_block_votes,
35 | },
36 | WrongEpoch: true,
37 | },
38 | },
39 | MisbehaviourProof{
40 | EpochVoteDoublesign: &EpochVoteDoublesign{
41 | Pair: [2]LlrSignedEpochVote{
42 | test_llr_signed_epoch_vote,
43 | test_llr_signed_epoch_vote,
44 | },
45 | },
46 | },
47 | MisbehaviourProof{
48 | WrongEpochVote: &WrongEpochVote{
49 | Pals: [2]LlrSignedEpochVote{
50 | test_llr_signed_epoch_vote,
51 | test_llr_signed_epoch_vote,
52 | },
53 | },
54 | },
55 | }
56 |
57 | require.Equal(t, "85834ef7fc1d75d65832b1f9b45b43c4f5677811bb2d384208553d32ab49def1", hex.EncodeToString(CalcMisbehaviourProofsHash(v).Bytes()))
58 | }
59 |
--------------------------------------------------------------------------------
/inter/gas_power_left.go:
--------------------------------------------------------------------------------
1 | package inter
2 |
3 | import "fmt"
4 |
5 | const (
6 | ShortTermGas = 0
7 | LongTermGas = 1
8 | GasPowerConfigs = 2
9 | )
10 |
11 | // GasPowerLeft is long-term gas power left and short-term gas power left
12 | type GasPowerLeft struct {
13 | Gas [GasPowerConfigs]uint64
14 | }
15 |
16 | // Add add to all gas power lefts
17 | func (g GasPowerLeft) Add(diff uint64) {
18 | for i := range g.Gas {
19 | g.Gas[i] += diff
20 | }
21 | }
22 |
23 | // Min returns minimum within long-term gas power left and short-term gas power left
24 | func (g GasPowerLeft) Min() uint64 {
25 | min := g.Gas[0]
26 | for _, gas := range g.Gas {
27 | if min > gas {
28 | min = gas
29 | }
30 | }
31 | return min
32 | }
33 |
34 | // Max returns maximum within long-term gas power left and short-term gas power left
35 | func (g GasPowerLeft) Max() uint64 {
36 | max := g.Gas[0]
37 | for _, gas := range g.Gas {
38 | if max < gas {
39 | max = gas
40 | }
41 | }
42 | return max
43 | }
44 |
45 | // Sub subtracts from all gas power lefts
46 | func (g GasPowerLeft) Sub(diff uint64) GasPowerLeft {
47 | cp := g
48 | for i := range cp.Gas {
49 | cp.Gas[i] -= diff
50 | }
51 | return cp
52 | }
53 |
54 | // String returns string representation.
55 | func (g GasPowerLeft) String() string {
56 | return fmt.Sprintf("{short=%d, long=%d}", g.Gas[ShortTermGas], g.Gas[LongTermGas])
57 | }
58 |
--------------------------------------------------------------------------------
/inter/gas_power_left_test.go:
--------------------------------------------------------------------------------
1 | package inter
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/ethereum/go-ethereum/common"
7 | "github.com/ethereum/go-ethereum/rlp"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestRlp(t *testing.T) {
12 | require := require.New(t)
13 | v := GasPowerLeft{
14 | Gas: [2]uint64{0xBAADCAFE, 0xDEADBEEF},
15 | }
16 | b, err := rlp.EncodeToBytes(v)
17 | require.NoError(err)
18 | require.Equal("cbca84baadcafe84deadbeef", common.Bytes2Hex(b))
19 | }
20 |
--------------------------------------------------------------------------------
/inter/iblockproc/legacy.go:
--------------------------------------------------------------------------------
1 | package iblockproc
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/hash"
5 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
6 | "github.com/Fantom-foundation/lachesis-base/inter/pos"
7 |
8 | "github.com/Fantom-foundation/go-opera/inter"
9 | "github.com/Fantom-foundation/go-opera/opera"
10 | )
11 |
12 | type ValidatorEpochStateV0 struct {
13 | GasRefund uint64
14 | PrevEpochEvent hash.Event
15 | }
16 |
17 | type EpochStateV0 struct {
18 | Epoch idx.Epoch
19 | EpochStart inter.Timestamp
20 | PrevEpochStart inter.Timestamp
21 |
22 | EpochStateRoot hash.Hash
23 |
24 | Validators *pos.Validators
25 | ValidatorStates []ValidatorEpochStateV0
26 | ValidatorProfiles ValidatorProfiles
27 |
28 | Rules opera.Rules
29 | }
30 |
--------------------------------------------------------------------------------
/inter/iblockproc/profiles.go:
--------------------------------------------------------------------------------
1 | package iblockproc
2 |
3 | import (
4 | "io"
5 | "math/big"
6 |
7 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
8 | "github.com/Fantom-foundation/lachesis-base/inter/pos"
9 | "github.com/ethereum/go-ethereum/rlp"
10 |
11 | "github.com/Fantom-foundation/go-opera/inter/drivertype"
12 | )
13 |
14 | type ValidatorProfiles map[idx.ValidatorID]drivertype.Validator
15 |
16 | func (vv ValidatorProfiles) Copy() ValidatorProfiles {
17 | cp := make(ValidatorProfiles, len(vv))
18 | for k, v := range vv {
19 | cpv := v
20 | cpv.Weight = new(big.Int).Set(cpv.Weight)
21 | cpv.PubKey = cpv.PubKey.Copy()
22 | cp[k] = cpv
23 | }
24 | return cp
25 | }
26 |
27 | func (vv ValidatorProfiles) SortedArray() []drivertype.ValidatorAndID {
28 | builder := pos.NewBigBuilder()
29 | for id, profile := range vv {
30 | builder.Set(id, profile.Weight)
31 | }
32 | validators := builder.Build()
33 | sortedIds := validators.SortedIDs()
34 | arr := make([]drivertype.ValidatorAndID, validators.Len())
35 | for i, id := range sortedIds {
36 | arr[i] = drivertype.ValidatorAndID{
37 | ValidatorID: id,
38 | Validator: vv[id],
39 | }
40 | }
41 | return arr
42 | }
43 |
44 | // EncodeRLP is for RLP serialization.
45 | func (vv ValidatorProfiles) EncodeRLP(w io.Writer) error {
46 | return rlp.Encode(w, vv.SortedArray())
47 | }
48 |
49 | // DecodeRLP is for RLP deserialization.
50 | func (vv *ValidatorProfiles) DecodeRLP(s *rlp.Stream) error {
51 | var arr []drivertype.ValidatorAndID
52 | if err := s.Decode(&arr); err != nil {
53 | return err
54 | }
55 |
56 | *vv = make(ValidatorProfiles, len(arr))
57 |
58 | for _, it := range arr {
59 | (*vv)[it.ValidatorID] = it.Validator
60 | }
61 |
62 | return nil
63 | }
64 |
--------------------------------------------------------------------------------
/inter/ibr/inter_block_records.go:
--------------------------------------------------------------------------------
1 | package ibr
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/common/bigendian"
5 | "github.com/Fantom-foundation/lachesis-base/hash"
6 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
7 | "github.com/ethereum/go-ethereum/core/types"
8 |
9 | "github.com/Fantom-foundation/go-opera/inter"
10 | )
11 |
12 | type LlrBlockVote struct {
13 | Atropos hash.Event
14 | Root hash.Hash
15 | TxHash hash.Hash
16 | ReceiptsHash hash.Hash
17 | Time inter.Timestamp
18 | GasUsed uint64
19 | }
20 |
21 | type LlrFullBlockRecord struct {
22 | Atropos hash.Event
23 | Root hash.Hash
24 | Txs types.Transactions
25 | Receipts []*types.ReceiptForStorage
26 | Time inter.Timestamp
27 | GasUsed uint64
28 | }
29 |
30 | type LlrIdxFullBlockRecord struct {
31 | LlrFullBlockRecord
32 | Idx idx.Block
33 | }
34 |
35 | func (bv LlrBlockVote) Hash() hash.Hash {
36 | return hash.Of(bv.Atropos.Bytes(), bv.Root.Bytes(), bv.TxHash.Bytes(), bv.ReceiptsHash.Bytes(), bv.Time.Bytes(), bigendian.Uint64ToBytes(bv.GasUsed))
37 | }
38 |
39 | func (br LlrFullBlockRecord) Hash() hash.Hash {
40 | return LlrBlockVote{
41 | Atropos: br.Atropos,
42 | Root: br.Root,
43 | TxHash: inter.CalcTxHash(br.Txs),
44 | ReceiptsHash: inter.CalcReceiptsHash(br.Receipts),
45 | Time: br.Time,
46 | GasUsed: br.GasUsed,
47 | }.Hash()
48 | }
49 |
--------------------------------------------------------------------------------
/inter/iep/inter_epoch_packs.go:
--------------------------------------------------------------------------------
1 | package iep
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/inter"
5 | "github.com/Fantom-foundation/go-opera/inter/ier"
6 | )
7 |
8 | type LlrEpochPack struct {
9 | Votes []inter.LlrSignedEpochVote
10 | Record ier.LlrIdxFullEpochRecord
11 | }
12 |
--------------------------------------------------------------------------------
/inter/ier/inter_epoch_records.go:
--------------------------------------------------------------------------------
1 | package ier
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/hash"
5 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
6 |
7 | "github.com/Fantom-foundation/go-opera/inter/iblockproc"
8 | )
9 |
10 | type LlrFullEpochRecord struct {
11 | BlockState iblockproc.BlockState
12 | EpochState iblockproc.EpochState
13 | }
14 |
15 | type LlrIdxFullEpochRecord struct {
16 | LlrFullEpochRecord
17 | Idx idx.Epoch
18 | }
19 |
20 | func (er LlrFullEpochRecord) Hash() hash.Hash {
21 | return hash.Of(er.BlockState.Hash().Bytes(), er.EpochState.Hash().Bytes())
22 | }
23 |
--------------------------------------------------------------------------------
/inter/inter_mps.go:
--------------------------------------------------------------------------------
1 | package inter
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/hash"
5 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
6 | )
7 |
8 | const (
9 | // MinAccomplicesForProof defines how many validators must have signed the same wrong vote.
10 | // Otherwise, wrong-signer is not liable as a protection against singular software/hardware failures
11 | MinAccomplicesForProof = 2
12 | )
13 |
14 | type EventsDoublesign struct {
15 | Pair [2]SignedEventLocator
16 | }
17 |
18 | type BlockVoteDoublesign struct {
19 | Block idx.Block
20 | Pair [2]LlrSignedBlockVotes
21 | }
22 |
23 | func (p BlockVoteDoublesign) GetVote(i int) hash.Hash {
24 | return p.Pair[i].Val.Votes[p.Block-p.Pair[i].Val.Start]
25 | }
26 |
27 | type WrongBlockVote struct {
28 | Block idx.Block
29 | Pals [MinAccomplicesForProof]LlrSignedBlockVotes
30 | WrongEpoch bool
31 | }
32 |
33 | func (p WrongBlockVote) GetVote(i int) hash.Hash {
34 | return p.Pals[i].Val.Votes[p.Block-p.Pals[i].Val.Start]
35 | }
36 |
37 | type EpochVoteDoublesign struct {
38 | Pair [2]LlrSignedEpochVote
39 | }
40 |
41 | type WrongEpochVote struct {
42 | Pals [MinAccomplicesForProof]LlrSignedEpochVote
43 | }
44 |
45 | type MisbehaviourProof struct {
46 | EventsDoublesign *EventsDoublesign `rlp:"nil"`
47 |
48 | BlockVoteDoublesign *BlockVoteDoublesign `rlp:"nil"`
49 |
50 | WrongBlockVote *WrongBlockVote `rlp:"nil"`
51 |
52 | EpochVoteDoublesign *EpochVoteDoublesign `rlp:"nil"`
53 |
54 | WrongEpochVote *WrongEpochVote `rlp:"nil"`
55 | }
56 |
--------------------------------------------------------------------------------
/inter/signature.go:
--------------------------------------------------------------------------------
1 | package inter
2 |
3 | const SigSize = 64
4 |
5 | // Signature is a secp256k1 signature in R|S format
6 | type Signature [SigSize]byte
7 |
8 | func (s Signature) Bytes() []byte {
9 | return s[:]
10 | }
11 |
12 | func BytesToSignature(b []byte) (sig Signature) {
13 | if len(b) != SigSize {
14 | panic("invalid signature length")
15 | }
16 | copy(sig[:], b)
17 | return sig
18 | }
19 |
--------------------------------------------------------------------------------
/inter/time.go:
--------------------------------------------------------------------------------
1 | package inter
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/common/bigendian"
7 | )
8 |
9 | type (
10 | // Timestamp is a UNIX nanoseconds timestamp
11 | Timestamp uint64
12 | )
13 |
14 | // Bytes gets the byte representation of the index.
15 | func (t Timestamp) Bytes() []byte {
16 | return bigendian.Uint64ToBytes(uint64(t))
17 | }
18 |
19 | // BytesToTimestamp converts bytes to timestamp.
20 | func BytesToTimestamp(b []byte) Timestamp {
21 | return Timestamp(bigendian.BytesToUint64(b))
22 | }
23 |
24 | func FromUnix(t int64) Timestamp {
25 | return Timestamp(int64(t) * int64(time.Second))
26 | }
27 |
28 | // Unix returns t as a Unix time, the number of seconds elapsed
29 | // since January 1, 1970 UTC. The result does not depend on the
30 | // location associated with t.
31 | func (t Timestamp) Unix() int64 {
32 | return int64(t) / int64(time.Second)
33 | }
34 |
35 | func (t Timestamp) Time() time.Time {
36 | return time.Unix(int64(t)/int64(time.Second), int64(t)%int64(time.Second))
37 | }
38 |
39 | // MaxTimestamp return max value.
40 | func MaxTimestamp(x, y Timestamp) Timestamp {
41 | if x > y {
42 | return x
43 | }
44 | return y
45 | }
46 |
--------------------------------------------------------------------------------
/inter/validatorpk/pubkey.go:
--------------------------------------------------------------------------------
1 | package validatorpk
2 |
3 | import (
4 | "github.com/ethereum/go-ethereum/common"
5 | "github.com/pkg/errors"
6 | )
7 |
8 | const (
9 | FakePassword = "fakepassword"
10 | )
11 |
12 | type PubKey struct {
13 | Type uint8
14 | Raw []byte
15 | }
16 |
17 | var Types = struct {
18 | Secp256k1 uint8
19 | }{
20 | Secp256k1: 0xc0,
21 | }
22 |
23 | func (pk PubKey) Empty() bool {
24 | return len(pk.Raw) == 0 && pk.Type == 0
25 | }
26 |
27 | func (pk PubKey) String() string {
28 | return "0x" + common.Bytes2Hex(pk.Bytes())
29 | }
30 |
31 | func (pk PubKey) Bytes() []byte {
32 | return append([]byte{pk.Type}, pk.Raw...)
33 | }
34 |
35 | func (pk PubKey) Copy() PubKey {
36 | return PubKey{
37 | Type: pk.Type,
38 | Raw: common.CopyBytes(pk.Raw),
39 | }
40 | }
41 |
42 | func FromString(str string) (PubKey, error) {
43 | return FromBytes(common.FromHex(str))
44 | }
45 |
46 | func FromBytes(b []byte) (PubKey, error) {
47 | if len(b) == 0 {
48 | return PubKey{}, errors.New("empty pubkey")
49 | }
50 | return PubKey{b[0], b[1:]}, nil
51 | }
52 |
53 | // MarshalText returns the hex representation of a.
54 | func (pk *PubKey) MarshalText() ([]byte, error) {
55 | return []byte(pk.String()), nil
56 | }
57 |
58 | // UnmarshalText parses a hash in hex syntax.
59 | func (pk *PubKey) UnmarshalText(input []byte) error {
60 | res, err := FromString(string(input))
61 | if err != nil {
62 | return err
63 | }
64 | *pk = res
65 | return nil
66 | }
67 |
--------------------------------------------------------------------------------
/logger/instance.go:
--------------------------------------------------------------------------------
1 | package logger
2 |
3 | import (
4 | "github.com/ethereum/go-ethereum/log"
5 | )
6 |
7 | type Instance struct {
8 | Log log.Logger
9 | }
10 |
11 | func New(name ...string) Instance {
12 | if len(name) == 0 {
13 | return Instance{
14 | Log: log.New(),
15 | }
16 | }
17 | return Instance{
18 | Log: log.New("module", name[0]),
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/logger/logger.go:
--------------------------------------------------------------------------------
1 | package logger
2 |
3 | import (
4 | "github.com/ethereum/go-ethereum/log"
5 | "github.com/evalphobia/logrus_sentry"
6 | )
7 |
8 | // init with defaults.
9 | func init() {
10 | log.Root().SetHandler(
11 | log.CallerStackHandler("%v", log.StdoutHandler))
12 | }
13 |
14 | // SetDSN appends sentry hook to log root handler.
15 | func SetDSN(value string) {
16 | // If DSN is empty, we don't create new hook.
17 | // Otherwise we'll the same error message for each new log.
18 | if value == "" {
19 | log.Warn("Sentry client DSN is empty")
20 | return
21 | }
22 |
23 | // TODO: find or make sentry log.Handler without logrus.
24 | sentry, err := logrus_sentry.NewSentryHook(value, nil)
25 | if err != nil {
26 | log.Warn("Probably Sentry host is not running", "err", err)
27 | return
28 | }
29 |
30 | log.Root().SetHandler(
31 | log.MultiHandler(
32 | log.Root().GetHandler(),
33 | LogrusHandler(sentry),
34 | ))
35 | }
36 |
37 | // SetLevel sets level filter on log root handler.
38 | // So it should be called last.
39 | func SetLevel(l string) {
40 | lvl, err := log.LvlFromString(l)
41 | if err != nil {
42 | panic(err)
43 | }
44 |
45 | log.Root().SetHandler(
46 | log.LvlFilterHandler(
47 | lvl,
48 | log.Root().GetHandler()))
49 | }
50 |
--------------------------------------------------------------------------------
/logger/logrus.go:
--------------------------------------------------------------------------------
1 | package logger
2 |
3 | import (
4 | "github.com/ethereum/go-ethereum/log"
5 | "github.com/sirupsen/logrus"
6 | )
7 |
8 | // LogrusHandler converts logrus hook to log handler.
9 | func LogrusHandler(hook logrus.Hook) log.Handler {
10 | return log.FuncHandler(func(r *log.Record) error {
11 | data := &logrus.Entry{
12 | Message: r.Msg,
13 | Data: fields(r.Ctx),
14 | }
15 | return hook.Fire(data)
16 | })
17 | }
18 |
19 | func fields(ctx []interface{}) logrus.Fields {
20 | ff := make(logrus.Fields, len(ctx)/2)
21 | for i := 1; i < len(ctx); i += 2 {
22 | k, ok := ctx[i-1].(string)
23 | if !ok {
24 | continue
25 | }
26 | ff[k] = ctx[i]
27 | }
28 |
29 | return ff
30 | }
31 |
--------------------------------------------------------------------------------
/logger/periodic_log.go:
--------------------------------------------------------------------------------
1 | package logger
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | // Periodic is the same as logger.Instance, but writes only once in a period
8 | type Periodic struct {
9 | Instance
10 | prevLogTime time.Time
11 | }
12 |
13 | // Info is timed log.Info
14 | func (l *Periodic) Info(period time.Duration, msg string, ctx ...interface{}) {
15 | if time.Since(l.prevLogTime) > period {
16 | l.Log.Info(msg, ctx...)
17 | l.prevLogTime = time.Now()
18 | }
19 | }
20 |
21 | // Warn is timed log.Warn
22 | func (l *Periodic) Warn(period time.Duration, msg string, ctx ...interface{}) {
23 | if time.Since(l.prevLogTime) > period {
24 | l.Log.Warn(msg, ctx...)
25 | l.prevLogTime = time.Now()
26 | }
27 | }
28 |
29 | // Error is timed log.Error
30 | func (l *Periodic) Error(period time.Duration, msg string, ctx ...interface{}) {
31 | if time.Since(l.prevLogTime) > period {
32 | l.Log.Error(msg, ctx...)
33 | l.prevLogTime = time.Now()
34 | }
35 | }
36 |
37 | // Debug is timed log.Debug
38 | func (l *Periodic) Debug(period time.Duration, msg string, ctx ...interface{}) {
39 | if time.Since(l.prevLogTime) > period {
40 | l.Log.Debug(msg, ctx...)
41 | l.prevLogTime = time.Now()
42 | }
43 | }
44 |
45 | // Trace is timed log.Trace
46 | func (l *Periodic) Trace(period time.Duration, msg string, ctx ...interface{}) {
47 | if time.Since(l.prevLogTime) > period {
48 | l.Log.Trace(msg, ctx...)
49 | l.prevLogTime = time.Now()
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/logger/test_output.go:
--------------------------------------------------------------------------------
1 | package logger
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/ethereum/go-ethereum/log"
7 | )
8 |
9 | // SetTestMode sets test mode.
10 | func SetTestMode(t testing.TB) {
11 | log.Root().SetHandler(
12 | log.CallerStackHandler("%v", TestHandler(t, log.LogfmtFormat())))
13 | }
14 |
15 | // TestHandler writes into test log.
16 | func TestHandler(t testing.TB, fmtr log.Format) log.Handler {
17 | return log.FuncHandler(func(r *log.Record) error {
18 | t.Log(string(fmtr.Format(r)))
19 | return nil
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/opera/contracts/driver/driver_predeploy.go:
--------------------------------------------------------------------------------
1 | package driver
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/gossip/contract/driver100"
5 | "github.com/ethereum/go-ethereum/common"
6 | "github.com/ethereum/go-ethereum/common/hexutil"
7 | )
8 |
9 | // GetContractBin is NodeDriver contract genesis implementation bin code
10 | // Has to be compiled with flag bin-runtime
11 | // Built from opera-sfc be4e79d5a5a425f08efd6d65b588a72ae90f706f, solc 0.5.17+commit.d19bba13.Emscripten.clang, optimize-runs 10000
12 | func GetContractBin() []byte {
13 | return hexutil.MustDecode(driver100.ContractBinRuntime)
14 | }
15 |
16 | // ContractAddress is the NodeDriver contract address
17 | var ContractAddress = common.HexToAddress("0xd100a01e00000000000000000000000000000000")
18 |
--------------------------------------------------------------------------------
/opera/contracts/driver/driverpos/positions.go:
--------------------------------------------------------------------------------
1 | package driverpos
2 |
3 | import (
4 | "github.com/ethereum/go-ethereum/common"
5 | "github.com/ethereum/go-ethereum/crypto"
6 | )
7 |
8 | // Events
9 | var (
10 | // Topics of Driver contract logs
11 | Topics = struct {
12 | UpdateValidatorWeight common.Hash
13 | UpdateValidatorPubkey common.Hash
14 | UpdateNetworkRules common.Hash
15 | UpdateNetworkVersion common.Hash
16 | AdvanceEpochs common.Hash
17 | }{
18 | UpdateValidatorWeight: crypto.Keccak256Hash([]byte("UpdateValidatorWeight(uint256,uint256)")),
19 | UpdateValidatorPubkey: crypto.Keccak256Hash([]byte("UpdateValidatorPubkey(uint256,bytes)")),
20 | UpdateNetworkRules: crypto.Keccak256Hash([]byte("UpdateNetworkRules(bytes)")),
21 | UpdateNetworkVersion: crypto.Keccak256Hash([]byte("UpdateNetworkVersion(uint256)")),
22 | AdvanceEpochs: crypto.Keccak256Hash([]byte("AdvanceEpochs(uint256)")),
23 | }
24 | )
25 |
--------------------------------------------------------------------------------
/opera/contracts/driverauth/driverauth.go:
--------------------------------------------------------------------------------
1 | package driverauth
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/gossip/contract/driverauth100"
5 | "github.com/ethereum/go-ethereum/common"
6 | "github.com/ethereum/go-ethereum/common/hexutil"
7 | )
8 |
9 | // GetContractBin is NodeDriverAuth contract genesis implementation bin code
10 | // Has to be compiled with flag bin-runtime
11 | // Built from opera-sfc be4e79d5a5a425f08efd6d65b588a72ae90f706f, solc 0.5.17+commit.d19bba13.Emscripten.clang, optimize-runs 10000
12 | func GetContractBin() []byte {
13 | return hexutil.MustDecode(driverauth100.ContractBinRuntime)
14 | }
15 |
16 | // ContractAddress is the NodeDriverAuth contract address
17 | var ContractAddress = common.HexToAddress("0xd100ae0000000000000000000000000000000000")
18 |
--------------------------------------------------------------------------------
/opera/contracts/emitterdriver/emitterdriver.go:
--------------------------------------------------------------------------------
1 | package emitterdriver
2 |
3 | import "github.com/ethereum/go-ethereum/common"
4 |
5 | // ContractAddress is the EmitterDriver contract address
6 | var ContractAddress = common.HexToAddress("0xee00d10000000000000000000000000000000000")
7 |
--------------------------------------------------------------------------------
/opera/contracts/evmwriter/evm_writer_test.go:
--------------------------------------------------------------------------------
1 | package evmwriter
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestSign(t *testing.T) {
10 | require := require.New(t)
11 |
12 | require.Equal([]byte{0xe3, 0x04, 0x43, 0xbc}, setBalanceMethodID)
13 | require.Equal([]byte{0xd6, 0xa0, 0xc7, 0xaf}, copyCodeMethodID)
14 | require.Equal([]byte{0x07, 0x69, 0x0b, 0x2a}, swapCodeMethodID)
15 | require.Equal([]byte{0x39, 0xe5, 0x03, 0xab}, setStorageMethodID)
16 | require.Equal([]byte{0x79, 0xbe, 0xad, 0x38}, incNonceMethodID)
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/opera/contracts/netinit/netinitcalls/network_initializer_calls.go:
--------------------------------------------------------------------------------
1 | package netinitcall
2 |
3 | import (
4 | "math/big"
5 | "strings"
6 |
7 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
8 | "github.com/ethereum/go-ethereum/accounts/abi"
9 | "github.com/ethereum/go-ethereum/common"
10 |
11 | "github.com/Fantom-foundation/go-opera/utils"
12 | )
13 |
14 | const ContractABI = "[{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"sealedEpoch\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"totalSupply\",\"type\":\"uint256\"},{\"internalType\":\"addresspayable\",\"name\":\"_sfc\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lib\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_auth\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_driver\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_evmWriter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"initializeAll\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"
15 |
16 | var (
17 | sAbi, _ = abi.JSON(strings.NewReader(ContractABI))
18 | )
19 |
20 | // Methods
21 |
22 | func InitializeAll(sealedEpoch idx.Epoch, totalSupply *big.Int, sfcAddr common.Address, libAddr common.Address, driverAuthAddr common.Address, driverAddr common.Address, evmWriterAddr common.Address, owner common.Address) []byte {
23 | data, _ := sAbi.Pack("initializeAll", utils.U64toBig(uint64(sealedEpoch)), totalSupply, sfcAddr, libAddr, driverAuthAddr, driverAddr, evmWriterAddr, owner)
24 | return data
25 | }
26 |
--------------------------------------------------------------------------------
/opera/contracts/netinit/network_initializer.go:
--------------------------------------------------------------------------------
1 | package netinit
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/gossip/contract/netinit100"
5 | "github.com/ethereum/go-ethereum/common"
6 | "github.com/ethereum/go-ethereum/common/hexutil"
7 | )
8 |
9 | // GetContractBin is NetworkInitializer contract genesis implementation bin code
10 | // Has to be compiled with flag bin-runtime
11 | // Built from opera-sfc be4e79d5a5a425f08efd6d65b588a72ae90f706f, solc 0.5.17+commit.d19bba13.Emscripten.clang, optimize-runs 10000
12 | func GetContractBin() []byte {
13 | return hexutil.MustDecode(netinit100.ContractBinRuntime)
14 | }
15 |
16 | // ContractAddress is the NetworkInitializer contract address
17 | var ContractAddress = common.HexToAddress("0xd1005eed00000000000000000000000000000000")
18 |
--------------------------------------------------------------------------------
/opera/contracts/sfc/sfc_predeploy.go:
--------------------------------------------------------------------------------
1 | package sfc
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/gossip/contract/sfc100"
5 | "github.com/ethereum/go-ethereum/common"
6 | "github.com/ethereum/go-ethereum/common/hexutil"
7 | )
8 |
9 | // GetContractBin is SFC contract genesis implementation bin code
10 | // Has to be compiled with flag bin-runtime
11 | // Built from opera-sfc be4e79d5a5a425f08efd6d65b588a72ae90f706f, solc 0.5.17+commit.d19bba13.Emscripten.clang, optimize-runs 200
12 | func GetContractBin() []byte {
13 | return hexutil.MustDecode(sfc100.ContractBinRuntime)
14 | }
15 |
16 | // ContractAddress is the SFC contract address
17 | var ContractAddress = common.HexToAddress("0xfc00face00000000000000000000000000000000")
18 |
--------------------------------------------------------------------------------
/opera/contracts/sfclib/sfclib_predeploy.go:
--------------------------------------------------------------------------------
1 | package sfclib
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/gossip/contract/sfclib100"
5 | "github.com/ethereum/go-ethereum/common"
6 | "github.com/ethereum/go-ethereum/common/hexutil"
7 | )
8 |
9 | // GetContractBin is SFCLib contract genesis implementation bin code
10 | // Has to be compiled with flag bin-runtime
11 | // Built from opera-sfc be4e79d5a5a425f08efd6d65b588a72ae90f706f, solc 0.5.17+commit.d19bba13.Emscripten.clang, optimize-runs 200
12 | func GetContractBin() []byte {
13 | return hexutil.MustDecode(sfclib100.ContractBinRuntime)
14 | }
15 |
16 | // ContractAddress is the SFCLib contract address
17 | var ContractAddress = common.HexToAddress("0xfc01face00000000000000000000000000000000")
18 |
--------------------------------------------------------------------------------
/opera/genesis/gpos/validators.go:
--------------------------------------------------------------------------------
1 | package gpos
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/inter"
5 | "github.com/ethereum/go-ethereum/common"
6 |
7 | "github.com/Fantom-foundation/go-opera/inter/validatorpk"
8 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
9 | )
10 |
11 | type (
12 | // Validator is a helper structure to define genesis validators
13 | Validator struct {
14 | ID idx.ValidatorID
15 | Address common.Address
16 | PubKey validatorpk.PubKey
17 | CreationTime inter.Timestamp
18 | CreationEpoch idx.Epoch
19 | DeactivatedTime inter.Timestamp
20 | DeactivatedEpoch idx.Epoch
21 | Status uint64
22 | }
23 |
24 | Validators []Validator
25 | )
26 |
27 | // Map converts Validators to map
28 | func (gv Validators) Map() map[idx.ValidatorID]Validator {
29 | validators := map[idx.ValidatorID]Validator{}
30 | for _, val := range gv {
31 | validators[val.ID] = val
32 | }
33 | return validators
34 | }
35 |
36 | // PubKeys returns not sorted genesis pub keys
37 | func (gv Validators) PubKeys() []validatorpk.PubKey {
38 | res := make([]validatorpk.PubKey, 0, len(gv))
39 | for _, v := range gv {
40 | res = append(res, v.PubKey)
41 | }
42 | return res
43 | }
44 |
45 | // Addresses returns not sorted genesis addresses
46 | func (gv Validators) Addresses() []common.Address {
47 | res := make([]common.Address, 0, len(gv))
48 | for _, v := range gv {
49 | res = append(res, v.Address)
50 | }
51 | return res
52 | }
53 |
--------------------------------------------------------------------------------
/opera/genesis/types.go:
--------------------------------------------------------------------------------
1 | package genesis
2 |
3 | import (
4 | "fmt"
5 | "sort"
6 | "strings"
7 |
8 | "github.com/Fantom-foundation/lachesis-base/hash"
9 |
10 | "github.com/Fantom-foundation/go-opera/inter/ibr"
11 | "github.com/Fantom-foundation/go-opera/inter/ier"
12 | )
13 |
14 | type (
15 | Hashes map[string]hash.Hash
16 | Header struct {
17 | GenesisID hash.Hash
18 | NetworkID uint64
19 | NetworkName string
20 | }
21 | Blocks interface {
22 | ForEach(fn func(ibr.LlrIdxFullBlockRecord) bool)
23 | }
24 | Epochs interface {
25 | ForEach(fn func(ier.LlrIdxFullEpochRecord) bool)
26 | }
27 | EvmItems interface {
28 | ForEach(fn func(key, value []byte) bool)
29 | }
30 | Genesis struct {
31 | Header
32 |
33 | Blocks Blocks
34 | Epochs Epochs
35 | RawEvmItems EvmItems
36 | }
37 | )
38 |
39 | func (hh Hashes) Includes(hh2 Hashes) bool {
40 | for n, h := range hh {
41 | if hh2[n] != h {
42 | return false
43 | }
44 | }
45 | return true
46 | }
47 |
48 | func (hh Hashes) Equal(hh2 Hashes) bool {
49 | return hh.Includes(hh2) && hh2.Includes(hh)
50 | }
51 |
52 | func (hh Hashes) String() string {
53 | bb := make([]string, 0, len(hh))
54 | for n, h := range hh {
55 | bb = append(bb, fmt.Sprintf("%s: %s", n, h.String()))
56 | }
57 | sort.Strings(bb)
58 | return "{" + strings.Join(bb, ", ") + "}"
59 | }
60 |
61 | func (h Header) Equal(h2 Header) bool {
62 | return h == h2
63 | }
64 |
65 | func (h Header) String() string {
66 | return fmt.Sprintf("{%d, net:%s, id:%s}", h.NetworkID, h.NetworkName, h.GenesisID.String())
67 | }
68 |
--------------------------------------------------------------------------------
/opera/genesisstore/filelog/filelog.go:
--------------------------------------------------------------------------------
1 | package filelog
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "time"
7 |
8 | "github.com/ethereum/go-ethereum/log"
9 |
10 | "github.com/Fantom-foundation/go-opera/utils"
11 | )
12 |
13 | type Filelog struct {
14 | io.Reader
15 | name string
16 | size uint64
17 | period time.Duration
18 | consumed uint64
19 | prevLog time.Time
20 | start time.Time
21 | }
22 |
23 | func (f *Filelog) Read(p []byte) (n int, err error) {
24 | n, err = f.Reader.Read(p)
25 | f.consumed += uint64(n)
26 | if f.prevLog.IsZero() {
27 | log.Info(fmt.Sprintf("- Reading %s", f.name))
28 | f.prevLog = time.Now()
29 | f.start = time.Now()
30 | } else if f.consumed > 0 && f.consumed < f.size && time.Since(f.prevLog) >= f.period {
31 | elapsed := time.Since(f.start)
32 | eta := float64(f.size-f.consumed) / float64(f.consumed) * float64(elapsed)
33 | progress := float64(f.consumed) / float64(f.size)
34 | eta *= 1.0 + (1.0-progress)/2.0 // show slightly higher ETA as performance degrades over larger volumes of data
35 | progressStr := fmt.Sprintf("%.2f%%", 100*progress)
36 | log.Info(fmt.Sprintf("- Reading %s", f.name), "progress", progressStr, "elapsed", utils.PrettyDuration(elapsed), "eta", utils.PrettyDuration(eta))
37 | f.prevLog = time.Now()
38 | }
39 | return
40 | }
41 |
42 | func Wrap(r io.Reader, name string, size uint64, period time.Duration) *Filelog {
43 | return &Filelog{
44 | Reader: r,
45 | name: name,
46 | size: size,
47 | period: period,
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/opera/genesisstore/fileshash/reader_map.go:
--------------------------------------------------------------------------------
1 | package fileshash
2 |
3 | import (
4 | "io"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/hash"
7 | )
8 |
9 | type Map struct {
10 | backend func(string) (io.Reader, error)
11 | }
12 |
13 | func Wrap(backend func(string) (io.Reader, error), maxMemoryUsage uint64, roots map[string]hash.Hash) func(string) (io.Reader, error) {
14 | return func(name string) (io.Reader, error) {
15 | root, ok := roots[name]
16 | if !ok {
17 | return nil, ErrRootNotFound
18 | }
19 | f, err := backend(name)
20 | if err != nil {
21 | return nil, err
22 | }
23 | return WrapReader(f, maxMemoryUsage, root), nil
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/opera/genesisstore/readersmap/reader_map.go:
--------------------------------------------------------------------------------
1 | package readersmap
2 |
3 | import (
4 | "errors"
5 | "io"
6 | )
7 |
8 | type Map map[string]io.Reader
9 |
10 | type Unit struct {
11 | Name string
12 | io.Reader
13 | }
14 |
15 | var (
16 | ErrNotFound = errors.New("not found")
17 | ErrDupFile = errors.New("unit name is duplicated")
18 | )
19 |
20 | func Wrap(rr []Unit) (Map, error) {
21 | units := make(Map)
22 | for _, r := range rr {
23 | if units[r.Name] != nil {
24 | return nil, ErrDupFile
25 | }
26 | units[r.Name] = r.Reader
27 | }
28 | return units, nil
29 | }
30 |
31 | func (mm Map) Open(name string) (io.Reader, error) {
32 | f := mm[name]
33 | if f == nil {
34 | return nil, ErrNotFound
35 | }
36 | return f, nil
37 | }
38 |
--------------------------------------------------------------------------------
/opera/genesisstore/store.go:
--------------------------------------------------------------------------------
1 | package genesisstore
2 |
3 | import (
4 | "io"
5 |
6 | "github.com/Fantom-foundation/go-opera/logger"
7 | "github.com/Fantom-foundation/go-opera/opera/genesis"
8 | )
9 |
10 | func BlocksSection(i int) string {
11 | return getSectionName("brs", i)
12 | }
13 |
14 | func EpochsSection(i int) string {
15 | return getSectionName("ers", i)
16 | }
17 |
18 | func EvmSection(i int) string {
19 | return getSectionName("evm", i)
20 | }
21 |
22 | type FilesMap func(string) (io.Reader, error)
23 |
24 | // Store is a node persistent storage working over a physical zip archive.
25 | type Store struct {
26 | fMap FilesMap
27 | head genesis.Header
28 | close func() error
29 |
30 | logger.Instance
31 | }
32 |
33 | // NewStore creates store over key-value db.
34 | func NewStore(fMap FilesMap, head genesis.Header, close func() error) *Store {
35 | return &Store{
36 | fMap: fMap,
37 | head: head,
38 | close: close,
39 | Instance: logger.New("genesis-store"),
40 | }
41 | }
42 |
43 | // Close leaves underlying database.
44 | func (s *Store) Close() error {
45 | s.fMap = nil
46 | return s.close()
47 | }
48 |
--------------------------------------------------------------------------------
/opera/marshal.go:
--------------------------------------------------------------------------------
1 | package opera
2 |
3 | import "encoding/json"
4 |
5 | func UpdateRules(src Rules, diff []byte) (res Rules, err error) {
6 | changed := src.Copy()
7 | err = json.Unmarshal(diff, &changed)
8 | if err != nil {
9 | return src, err
10 | }
11 | // protect readonly fields
12 | res = changed
13 | res.NetworkID = src.NetworkID
14 | res.Name = src.Name
15 | return
16 | }
17 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | sonar.projectKey=Fantom-foundation_go-opera
2 | sonar.projectName=go-opera
3 |
4 | sonar.sources=.
5 | sonar.exclusions=**/*_test.go,**/vendor/**
6 |
7 | sonar.tests=.
8 | sonar.test.inclusions=**/*_test.go
9 | sonar.test.exclusions=**/vendor/**
10 |
--------------------------------------------------------------------------------
/system/etc/default/x1:
--------------------------------------------------------------------------------
1 | # Add additional options to the command line
2 | X1_OPTS=""
3 |
--------------------------------------------------------------------------------
/system/etc/x1/config.toml:
--------------------------------------------------------------------------------
1 | [Node]
2 | Testnet = true
3 |
4 | [Node.P2P]
5 | ListenAddr = ":5050"
6 |
7 | # Share you node info with the xenblocks.io explorer
8 | # (optional) comment out to disable
9 | [XenBlocks]
10 | Endpoint = "ws://xenblocks.io:6668"
11 |
--------------------------------------------------------------------------------
/system/lib/systemd/system/x1.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=X1
3 | After=syslog.target network.target
4 |
5 | [Service]
6 | User=x1
7 | Group=x1
8 | Type=simple
9 | WorkingDirectory=~
10 | LimitNOFILE=infinity
11 | EnvironmentFile=-/etc/default/x1
12 | KillMode=process
13 | KillSignal=SIGINT
14 | TimeoutStopSec=600
15 | Restart=on-failure
16 | RestartSec=10s
17 | SyslogIdentifier=x1
18 | ExecStart=/usr/local/bin/x1 --config /etc/x1/config.toml $X1_OPTS
19 |
20 | [Install]
21 | WantedBy=multi-user.target
22 |
--------------------------------------------------------------------------------
/system/usr/share/x1/configs/testnet/api-node.toml:
--------------------------------------------------------------------------------
1 | [Node]
2 | Testnet = true
3 |
4 | # RPC server
5 | HTTPHost = "0.0.0.0"
6 | HTTPVirtualHosts = ["*"]
7 | HTTPCors = ["*"]
8 | HTTPPort = 8545
9 | HTTPModules = [
10 | "eth",
11 | "ftm",
12 | "dag",
13 | "abft",
14 | "web3",
15 | "net",
16 | "txpool"
17 | ]
18 |
19 | # Websocket server
20 | WSHost = "0.0.0.0"
21 | WSPort = 8546
22 | WSOrigins = ["*"]
23 | WSModules = [
24 | "eth",
25 | "ftm",
26 | "dag",
27 | "abft",
28 | "web3",
29 | "net",
30 | "txpool",
31 | ]
32 |
33 | [Node.P2P]
34 | ListenAddr = ":5050"
35 |
36 | # Share you node info with the xenblocks.io explorer
37 | # (optional) comment out to disable
38 | [XenBlocks]
39 | Endpoint = "ws://xenblocks.io:6668"
40 |
--------------------------------------------------------------------------------
/system/usr/share/x1/configs/testnet/archive-node.toml:
--------------------------------------------------------------------------------
1 | [Node]
2 | Testnet = true
3 |
4 | [Node.P2P]
5 | ListenAddr = ":5050"
6 |
7 | [OperaStore.EVM.Cache]
8 | TrieDirtyDisabled = true
9 | GreedyGC = false
10 |
11 | # Share you node info with the xenblocks.io explorer
12 | # (optional) comment out to disable
13 | [XenBlocks]
14 | Endpoint = "ws://xenblocks.io:6668"
15 |
--------------------------------------------------------------------------------
/system/usr/share/x1/configs/testnet/full-node.toml:
--------------------------------------------------------------------------------
1 | [Node]
2 | Testnet = true
3 |
4 | [Node.P2P]
5 | ListenAddr = ":5050"
6 |
7 | # Share you node info with the xenblocks.io explorer
8 | # (optional) comment out to disable
9 | [XenBlocks]
10 | Endpoint = "ws://xenblocks.io:6668"
11 |
--------------------------------------------------------------------------------
/system/usr/share/x1/configs/testnet/validator-node.toml:
--------------------------------------------------------------------------------
1 | [Node]
2 | Testnet = true
3 |
4 | [Node.P2P]
5 | ListenAddr = ":5050"
6 |
7 | [Emitter.Validator]
8 |
9 | # update with your validator ID
10 | ID = 0
11 |
12 | # update with your validator public key
13 | PubKeyString = ""
14 |
15 | # update with your validator password file path
16 | PasswordFilePath = ""
17 |
18 | # Share you node info with the xenblocks.io explorer
19 | # (optional) comment out to disable
20 | [XenBlocks]
21 | Endpoint = "ws://xenblocks.io:6668"
22 |
--------------------------------------------------------------------------------
/system/x1-post-install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | # create an empty config if it doesn't exist
5 | if [ -d /etc ]; then
6 | if [ ! -d /etc/x1 ]; then
7 | mkdir -p /etc/x1 2>/dev/null || true
8 | fi
9 |
10 | if [ ! -f /etc/x1/config.toml ]; then
11 | cp system/etc/x1/config.toml /etc/x1/config.toml
12 | fi
13 |
14 | if [ -d /etc/default ] && [ ! -f /etc/default/x1 ]; then
15 | cp system/etc/default/x1 /etc/default/x1
16 | fi
17 | fi
18 |
19 | if [ -d /run/systemd/system ] && [ -d /etc/systemd/system/ ]; then
20 | systemctl daemon-reload
21 | systemctl try-restart x1
22 | fi
23 |
--------------------------------------------------------------------------------
/system/x1-pre-install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | PKG="x1"
5 |
6 | if [ -x "$(command -v useradd)" ]; then
7 | if ! getent passwd $PKG >/dev/null ; then
8 | useradd --system --user-group --create-home --home-dir /var/lib/$PKG $PKG
9 | echo "Created system user $PKG"
10 | fi
11 | fi
12 |
--------------------------------------------------------------------------------
/topicsdb/key_test.go:
--------------------------------------------------------------------------------
1 | package topicsdb
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestPosToBytes(t *testing.T) {
10 | require := require.New(t)
11 |
12 | for i := 0xff / 0x0f; i >= 0; i-- {
13 | expect := uint8(0x0f * i)
14 | bb := posToBytes(expect)
15 | got := bytesToPos(bb)
16 |
17 | require.Equal(expect, got)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/topicsdb/record.go:
--------------------------------------------------------------------------------
1 | package topicsdb
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/kvdb"
5 | "github.com/ethereum/go-ethereum/common"
6 | "github.com/ethereum/go-ethereum/core/types"
7 | )
8 |
9 | type (
10 | logrec struct {
11 | ID ID
12 | topicsCount uint8
13 | result *types.Log
14 | err error
15 |
16 | matched int
17 | }
18 | )
19 |
20 | func newLogrec(rec ID, topicCount uint8) *logrec {
21 | return &logrec{
22 | ID: rec,
23 | topicsCount: topicCount,
24 | }
25 | }
26 |
27 | // fetch record's data.
28 | func (rec *logrec) fetch(
29 | logrecTable kvdb.Reader,
30 | ) {
31 | r := &types.Log{
32 | BlockNumber: rec.ID.BlockNumber(),
33 | TxHash: rec.ID.TxHash(),
34 | Index: rec.ID.Index(),
35 | Topics: make([]common.Hash, rec.topicsCount),
36 | }
37 |
38 | var (
39 | buf []byte
40 | offset int
41 | )
42 | buf, rec.err = logrecTable.Get(rec.ID.Bytes())
43 | if rec.err != nil {
44 | return
45 | }
46 |
47 | // topics
48 | for i := 0; i < len(r.Topics); i++ {
49 | r.Topics[i] = common.BytesToHash(buf[offset : offset+common.HashLength])
50 | offset += common.HashLength
51 | }
52 |
53 | // fields
54 | r.BlockHash = common.BytesToHash(buf[offset : offset+common.HashLength])
55 | offset += common.HashLength
56 | r.Address = common.BytesToAddress(buf[offset : offset+common.AddressLength])
57 | offset += common.AddressLength
58 | r.Data = buf[offset:]
59 |
60 | rec.result = r
61 | return
62 | }
63 |
--------------------------------------------------------------------------------
/topicsdb/search_test.go:
--------------------------------------------------------------------------------
1 | package topicsdb
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
8 | "github.com/ethereum/go-ethereum/common"
9 | "github.com/ethereum/go-ethereum/core/types"
10 | "github.com/stretchr/testify/require"
11 | )
12 |
13 | func BenchmarkSearch(b *testing.B) {
14 | topics, recs, topics4rec := genTestData(1000)
15 |
16 | index := newTestIndex()
17 |
18 | for _, rec := range recs {
19 | err := index.Push(rec)
20 | require.NoError(b, err)
21 | }
22 |
23 | var query [][][]common.Hash
24 | for i := 0; i < len(topics); i++ {
25 | from, to := topics4rec(i)
26 | tt := topics[from : to-1]
27 |
28 | qq := make([][]common.Hash, len(tt))
29 | for pos, t := range tt {
30 | qq[pos] = []common.Hash{t}
31 | }
32 |
33 | query = append(query, qq)
34 | }
35 |
36 | pooled := withThreadPool{index}
37 |
38 | for dsc, method := range map[string]func(context.Context, idx.Block, idx.Block, [][]common.Hash) ([]*types.Log, error){
39 | "index": index.FindInBlocks,
40 | "pooled": pooled.FindInBlocks,
41 | } {
42 | b.Run(dsc, func(b *testing.B) {
43 | b.ResetTimer()
44 |
45 | for i := 0; i < b.N; i++ {
46 | qq := query[i%len(query)]
47 | _, err := method(nil, 0, 0xffffffff, qq)
48 | require.NoError(b, err)
49 | }
50 | })
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/tracing/tx-tracing.go:
--------------------------------------------------------------------------------
1 | package tracing
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/ethereum/go-ethereum/common"
7 | "github.com/opentracing/opentracing-go"
8 | )
9 |
10 | var (
11 | enabled bool
12 | txSpans = make(map[common.Hash]opentracing.Span)
13 | txSpansMu sync.RWMutex
14 |
15 | noopSpan = opentracing.NoopTracer{}.StartSpan("")
16 | )
17 |
18 | func SetEnabled(val bool) {
19 | enabled = val
20 | }
21 |
22 | func Enabled() bool {
23 | return enabled
24 | }
25 |
26 | func StartTx(tx common.Hash, operation string) {
27 | if !enabled {
28 | return
29 | }
30 |
31 | txSpansMu.Lock()
32 | defer txSpansMu.Unlock()
33 |
34 | if _, ok := txSpans[tx]; ok {
35 | return
36 | }
37 |
38 | span := opentracing.StartSpan("lifecycle")
39 | span.SetTag("txhash", tx.String())
40 | span.SetTag("enter", operation)
41 | txSpans[tx] = span
42 | }
43 |
44 | func FinishTx(tx common.Hash, operation string) {
45 | if !enabled {
46 | return
47 | }
48 |
49 | txSpansMu.Lock()
50 | defer txSpansMu.Unlock()
51 |
52 | span, ok := txSpans[tx]
53 | if !ok {
54 | return
55 | }
56 |
57 | span.SetTag("exit", operation)
58 | span.Finish()
59 | delete(txSpans, tx)
60 | }
61 |
62 | func CheckTx(tx common.Hash, operation string) opentracing.Span {
63 | if !enabled {
64 | return noopSpan
65 | }
66 |
67 | txSpansMu.RLock()
68 | defer txSpansMu.RUnlock()
69 |
70 | span, ok := txSpans[tx]
71 |
72 | if !ok {
73 | return noopSpan
74 | }
75 |
76 | return opentracing.GlobalTracer().StartSpan(
77 | operation,
78 | opentracing.ChildOf(span.Context()),
79 | )
80 | }
81 |
--------------------------------------------------------------------------------
/utils/adapters/ethdb2kvdb/adapter.go:
--------------------------------------------------------------------------------
1 | package ethdb2kvdb
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/kvdb"
5 | "github.com/ethereum/go-ethereum/ethdb"
6 | )
7 |
8 | type Adapter struct {
9 | ethdb.KeyValueStore
10 | }
11 |
12 | var _ kvdb.Store = (*Adapter)(nil)
13 |
14 | func Wrap(v ethdb.KeyValueStore) *Adapter {
15 | return &Adapter{v}
16 | }
17 |
18 | func (db *Adapter) Drop() {
19 | panic("called Drop on ethdb")
20 | }
21 |
22 | // batch is a write-only memory batch that commits changes to its host
23 | // database when Write is called. A batch cannot be used concurrently.
24 | type batch struct {
25 | ethdb.Batch
26 | }
27 |
28 | // Replay replays the batch contents.
29 | func (b *batch) Replay(w kvdb.Writer) error {
30 | return b.Batch.Replay(w)
31 | }
32 |
33 | // NewBatch creates a write-only key-value store that buffers changes to its host
34 | // database until a final write is called.
35 | func (db *Adapter) NewBatch() kvdb.Batch {
36 | return &batch{db.KeyValueStore.NewBatch()}
37 | }
38 |
39 | func (db *Adapter) GetSnapshot() (kvdb.Snapshot, error) {
40 | panic("called GetSnapshot on ethdb")
41 | return nil, nil
42 | }
43 |
44 | // NewIterator creates a binary-alphabetical iterator over a subset
45 | // of database content with a particular key prefix, starting at a particular
46 | // initial key (or after, if it does not exist).
47 | func (db *Adapter) NewIterator(prefix []byte, start []byte) kvdb.Iterator {
48 | return db.KeyValueStore.NewIterator(prefix, start)
49 | }
50 |
--------------------------------------------------------------------------------
/utils/adapters/kvdb2ethdb/adapter.go:
--------------------------------------------------------------------------------
1 | package kvdb2ethdb
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/kvdb"
5 | "github.com/ethereum/go-ethereum/ethdb"
6 | )
7 |
8 | type Adapter struct {
9 | kvdb.Store
10 | }
11 |
12 | var _ ethdb.KeyValueStore = (*Adapter)(nil)
13 |
14 | func Wrap(v kvdb.Store) *Adapter {
15 | return &Adapter{v}
16 | }
17 |
18 | // batch is a write-only memory batch that commits changes to its host
19 | // database when Write is called. A batch cannot be used concurrently.
20 | type batch struct {
21 | kvdb.Batch
22 | }
23 |
24 | // Replay replays the batch contents.
25 | func (b *batch) Replay(w ethdb.KeyValueWriter) error {
26 | return b.Batch.Replay(w)
27 | }
28 |
29 | // NewBatch creates a write-only key-value store that buffers changes to its host
30 | // database until a final write is called.
31 | func (db *Adapter) NewBatch() ethdb.Batch {
32 | return &batch{db.Store.NewBatch()}
33 | }
34 |
35 | // NewIterator creates a binary-alphabetical iterator over a subset
36 | // of database content with a particular key prefix, starting at a particular
37 | // initial key (or after, if it does not exist).
38 | func (db *Adapter) NewIterator(prefix []byte, start []byte) ethdb.Iterator {
39 | return db.Store.NewIterator(prefix, start)
40 | }
41 |
--------------------------------------------------------------------------------
/utils/adapters/snap2kvdb/adapter.go:
--------------------------------------------------------------------------------
1 | package snap2kvdb
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/kvdb"
5 | "github.com/Fantom-foundation/lachesis-base/kvdb/devnulldb"
6 | "github.com/ethereum/go-ethereum/log"
7 | )
8 |
9 | type Adapter struct {
10 | kvdb.Snapshot
11 | }
12 |
13 | var _ kvdb.Store = (*Adapter)(nil)
14 |
15 | func Wrap(v kvdb.Snapshot) *Adapter {
16 | return &Adapter{v}
17 | }
18 |
19 | func (db *Adapter) Put(key []byte, value []byte) error {
20 | log.Warn("called Put on snapshot")
21 | return nil
22 | }
23 |
24 | func (db *Adapter) Delete(key []byte) error {
25 | log.Warn("called Delete on snapshot")
26 | return nil
27 | }
28 |
29 | func (db *Adapter) GetSnapshot() (kvdb.Snapshot, error) {
30 | return db.Snapshot, nil
31 | }
32 |
33 | func (db *Adapter) NewBatch() kvdb.Batch {
34 | log.Warn("called NewBatch on snapshot")
35 | return devnulldb.New().NewBatch()
36 | }
37 |
38 | func (db *Adapter) Compact(start []byte, limit []byte) error {
39 | return nil
40 | }
41 |
42 | func (db *Adapter) Close() error {
43 | return nil
44 | }
45 |
46 | func (db *Adapter) Drop() {}
47 |
48 | func (db *Adapter) Stat(property string) (string, error) {
49 | return "", nil
50 | }
51 |
--------------------------------------------------------------------------------
/utils/adapters/vecmt2dagidx/vecmt2lachesis.go:
--------------------------------------------------------------------------------
1 | package vecmt2dagidx
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/abft"
5 | "github.com/Fantom-foundation/lachesis-base/abft/dagidx"
6 | "github.com/Fantom-foundation/lachesis-base/hash"
7 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
8 | "github.com/Fantom-foundation/lachesis-base/vecfc"
9 |
10 | "github.com/Fantom-foundation/go-opera/vecmt"
11 | )
12 |
13 | type Adapter struct {
14 | *vecmt.Index
15 | }
16 |
17 | var _ abft.DagIndex = (*Adapter)(nil)
18 |
19 | type AdapterSeq struct {
20 | *vecmt.HighestBefore
21 | }
22 |
23 | type BranchSeq struct {
24 | vecfc.BranchSeq
25 | }
26 |
27 | // Seq is a maximum observed e.Seq in the branch
28 | func (b *BranchSeq) Seq() idx.Event {
29 | return b.BranchSeq.Seq
30 | }
31 |
32 | // MinSeq is a minimum observed e.Seq in the branch
33 | func (b *BranchSeq) MinSeq() idx.Event {
34 | return b.BranchSeq.MinSeq
35 | }
36 |
37 | // Size of the vector clock
38 | func (b AdapterSeq) Size() int {
39 | return b.VSeq.Size()
40 | }
41 |
42 | // Get i's position in the byte-encoded vector clock
43 | func (b AdapterSeq) Get(i idx.Validator) dagidx.Seq {
44 | seq := b.HighestBefore.VSeq.Get(i)
45 | return &BranchSeq{seq}
46 | }
47 |
48 | func (v *Adapter) GetMergedHighestBefore(id hash.Event) dagidx.HighestBeforeSeq {
49 | return AdapterSeq{v.Index.GetMergedHighestBefore(id)}
50 | }
51 |
52 | func Wrap(v *vecmt.Index) *Adapter {
53 | return &Adapter{v}
54 | }
55 |
--------------------------------------------------------------------------------
/utils/bitmap/bitset.go:
--------------------------------------------------------------------------------
1 | package bitmap
2 |
3 | import "github.com/ethereum/go-ethereum/log"
4 |
5 | type Set []byte
6 |
7 | func New(max int) Set {
8 | l := max / 8
9 | if max%8 != 0 {
10 | l++
11 | }
12 | return make(Set, l)
13 | }
14 |
15 | func (s Set) Put(i int) {
16 | yi := i / 8
17 | bi := i % 8
18 |
19 | if yi >= len(s) {
20 | log.Debug("Index out of range", "index", i, "max", len(s)*8)
21 | return
22 | }
23 |
24 | s[yi] |= 1 << bi
25 | }
26 |
27 | func (s Set) Del(i int) {
28 | yi := i / 8
29 | bi := i % 8
30 |
31 | if yi >= len(s) {
32 | log.Debug("Index out of range", "index", i, "max", len(s)*8)
33 | return
34 | }
35 |
36 | s[yi] &= ^(1 << bi)
37 | }
38 |
39 | func (s Set) Has(i int) bool {
40 | yi := i / 8
41 | bi := i % 8
42 |
43 | if yi >= len(s) {
44 | log.Debug("Index out of range", "index", i, "max", len(s)*8)
45 | return false
46 | }
47 |
48 | return (s[yi] & (1 << bi)) != 0
49 | }
50 |
--------------------------------------------------------------------------------
/utils/concurrent/ValidatorBlocksSet.go:
--------------------------------------------------------------------------------
1 | package concurrent
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
7 | )
8 |
9 | type ValidatorBlocksSet struct {
10 | sync.RWMutex
11 | Val map[idx.ValidatorID]idx.Block
12 | }
13 |
14 | func WrapValidatorBlocksSet(v map[idx.ValidatorID]idx.Block) *ValidatorBlocksSet {
15 | return &ValidatorBlocksSet{
16 | RWMutex: sync.RWMutex{},
17 | Val: v,
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/utils/concurrent/ValidatorEpochsSet.go:
--------------------------------------------------------------------------------
1 | package concurrent
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
7 | )
8 |
9 | type ValidatorEpochsSet struct {
10 | sync.RWMutex
11 | Val map[idx.ValidatorID]idx.Epoch
12 | }
13 |
14 | func WrapValidatorEpochsSet(v map[idx.ValidatorID]idx.Epoch) *ValidatorEpochsSet {
15 | return &ValidatorEpochsSet{
16 | RWMutex: sync.RWMutex{},
17 | Val: v,
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/utils/concurrent/ValidatorEventsSet.go:
--------------------------------------------------------------------------------
1 | package concurrent
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/hash"
7 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
8 | )
9 |
10 | type ValidatorEventsSet struct {
11 | sync.RWMutex
12 | Val map[idx.ValidatorID]hash.Event
13 | }
14 |
15 | func WrapValidatorEventsSet(v map[idx.ValidatorID]hash.Event) *ValidatorEventsSet {
16 | return &ValidatorEventsSet{
17 | RWMutex: sync.RWMutex{},
18 | Val: v,
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/utils/concurrent/events.go:
--------------------------------------------------------------------------------
1 | package concurrent
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/hash"
7 | )
8 |
9 | type EventsSet struct {
10 | sync.RWMutex
11 | Val hash.EventsSet
12 | }
13 |
14 | func WrapEventsSet(v hash.EventsSet) *EventsSet {
15 | return &EventsSet{
16 | RWMutex: sync.RWMutex{},
17 | Val: v,
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/utils/dbutil/asyncflushproducer/producer.go:
--------------------------------------------------------------------------------
1 | package asyncflushproducer
2 |
3 | import (
4 | "errors"
5 | "sync"
6 |
7 | "github.com/Fantom-foundation/lachesis-base/kvdb"
8 | "github.com/ethereum/go-ethereum/metrics"
9 | )
10 |
11 | type Producer struct {
12 | kvdb.FullDBProducer
13 | mu sync.Mutex
14 | dbs map[string]*store
15 | stats metrics.Meter
16 |
17 | threshold uint64
18 | }
19 |
20 | func Wrap(backend kvdb.FullDBProducer, threshold uint64) *Producer {
21 | return &Producer{
22 | stats: metrics.NewMeterForced(),
23 | FullDBProducer: backend,
24 | dbs: make(map[string]*store),
25 | threshold: threshold,
26 | }
27 | }
28 |
29 | func (f *Producer) OpenDB(name string) (kvdb.Store, error) {
30 | f.mu.Lock()
31 | defer f.mu.Unlock()
32 | // open existing DB
33 | openedDB := f.dbs[name]
34 | if openedDB != nil {
35 | return openedDB, nil
36 | }
37 | // create new DB
38 | db, err := f.FullDBProducer.OpenDB(name)
39 | if err != nil {
40 | return nil, err
41 | }
42 | if f.dbs[name] != nil {
43 | return nil, errors.New("already opened")
44 | }
45 | wrapped := &store{
46 | Store: db,
47 | CloseFn: func() error {
48 | f.mu.Lock()
49 | delete(f.dbs, name)
50 | f.mu.Unlock()
51 | return db.Close()
52 | },
53 | }
54 | f.dbs[name] = wrapped
55 | return wrapped, nil
56 | }
57 |
58 | func (f *Producer) Flush(id []byte) error {
59 | f.stats.Mark(int64(f.FullDBProducer.NotFlushedSizeEst()))
60 |
61 | err := f.FullDBProducer.Flush(id)
62 | if err != nil {
63 | return err
64 | }
65 |
66 | // trigger flushing data to disk if throughput is below a threshold
67 | if uint64(f.stats.Rate1()) <= f.threshold {
68 | go func() {
69 | f.mu.Lock()
70 | defer f.mu.Unlock()
71 | for _, db := range f.dbs {
72 | _, _ = db.Stat("async_flush")
73 | }
74 | }()
75 | }
76 |
77 | return nil
78 | }
79 |
--------------------------------------------------------------------------------
/utils/dbutil/asyncflushproducer/store.go:
--------------------------------------------------------------------------------
1 | package asyncflushproducer
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/kvdb"
5 | )
6 |
7 | type store struct {
8 | kvdb.Store
9 | CloseFn func() error
10 | }
11 |
12 | func (s *store) Close() error {
13 | return s.CloseFn()
14 | }
15 |
--------------------------------------------------------------------------------
/utils/dbutil/compactdb/log.go:
--------------------------------------------------------------------------------
1 | package compactdb
2 |
3 | import (
4 | "sync"
5 | "sync/atomic"
6 | "time"
7 |
8 | "github.com/Fantom-foundation/lachesis-base/kvdb"
9 | "github.com/ethereum/go-ethereum/log"
10 | "github.com/status-im/keycard-go/hexutils"
11 | )
12 |
13 | type loggedCompacter struct {
14 | kvdb.Store
15 | name string
16 |
17 | currentOp atomic.Value
18 |
19 | wg sync.WaitGroup
20 | quit chan struct{}
21 | }
22 |
23 | type pair struct {
24 | p, l []byte
25 | }
26 |
27 | func (s *loggedCompacter) Compact(prev []byte, limit []byte) error {
28 | s.currentOp.Store(pair{prev, limit})
29 | if err := s.Store.Compact(prev, limit); err != nil {
30 | log.Error("Compaction error", "name", s.name, "err", err)
31 | return err
32 | }
33 | return nil
34 | }
35 |
36 | func (s *loggedCompacter) StartLogging() {
37 | s.wg.Add(1)
38 | go func() {
39 | defer s.wg.Done()
40 | ticker := time.NewTicker(time.Minute)
41 | for {
42 | select {
43 | case <-ticker.C:
44 | opI := s.currentOp.Load()
45 | if opI != nil {
46 | op := opI.(pair)
47 | // trim keys for nicer human-readable logging
48 | op.p, op.l = trimAfterDiff(op.p, op.l, 2)
49 | untilStr := hexutils.BytesToHex(op.l)
50 | if len(op.l) == 0 {
51 | untilStr = "end"
52 | }
53 | log.Info("Compacting DB", "name", s.name, "until", untilStr)
54 | }
55 | case <-s.quit:
56 | return
57 | }
58 | }
59 | }()
60 | }
61 |
62 | func (s *loggedCompacter) StopLogging() {
63 | close(s.quit)
64 | s.wg.Wait()
65 | }
66 |
--------------------------------------------------------------------------------
/utils/dbutil/itergc/iterator_gc.go:
--------------------------------------------------------------------------------
1 | package itergc
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/kvdb"
7 | )
8 |
9 | type Snapshot struct {
10 | kvdb.Snapshot
11 | nextID uint64
12 | iters map[uint64]kvdb.Iterator
13 | mu sync.Locker
14 | }
15 |
16 | type Iterator struct {
17 | kvdb.Iterator
18 | mu sync.Locker
19 | id uint64
20 | iters map[uint64]kvdb.Iterator
21 | }
22 |
23 | // Wrap snapshot to automatically close all pending iterators upon snapshot release
24 | func Wrap(snapshot kvdb.Snapshot, mu sync.Locker) *Snapshot {
25 | return &Snapshot{
26 | Snapshot: snapshot,
27 | iters: make(map[uint64]kvdb.Iterator),
28 | mu: mu,
29 | }
30 | }
31 |
32 | func (s *Snapshot) NewIterator(prefix []byte, start []byte) kvdb.Iterator {
33 | s.mu.Lock()
34 | defer s.mu.Unlock()
35 | it := s.Snapshot.NewIterator(prefix, start)
36 | id := s.nextID
37 | s.iters[id] = it
38 | s.nextID++
39 |
40 | return &Iterator{
41 | Iterator: it,
42 | mu: s.mu,
43 | id: id,
44 | iters: s.iters,
45 | }
46 | }
47 |
48 | func (s *Iterator) Release() {
49 | s.mu.Lock()
50 | defer s.mu.Unlock()
51 | s.Iterator.Release()
52 | delete(s.iters, s.id)
53 | }
54 |
55 | func (s *Snapshot) Release() {
56 | s.mu.Lock()
57 | defer s.mu.Unlock()
58 | // release all pending iterators
59 | for _, it := range s.iters {
60 | it.Release()
61 | }
62 | s.iters = nil
63 | s.Snapshot.Release()
64 | }
65 |
--------------------------------------------------------------------------------
/utils/dbutil/threads/counted.go:
--------------------------------------------------------------------------------
1 | package threads
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/kvdb"
5 |
6 | "github.com/Fantom-foundation/go-opera/logger"
7 | )
8 |
9 | type (
10 | countedDbProducer struct {
11 | kvdb.DBProducer
12 | }
13 |
14 | countedFullDbProducer struct {
15 | kvdb.FullDBProducer
16 | }
17 |
18 | countedStore struct {
19 | kvdb.Store
20 | }
21 |
22 | countedIterator struct {
23 | kvdb.Iterator
24 | release func(count int)
25 | }
26 | )
27 |
28 | func CountedDBProducer(dbs kvdb.DBProducer) kvdb.DBProducer {
29 | return &countedDbProducer{dbs}
30 | }
31 |
32 | func CountedFullDBProducer(dbs kvdb.FullDBProducer) kvdb.FullDBProducer {
33 | return &countedFullDbProducer{dbs}
34 | }
35 |
36 | func (p *countedDbProducer) OpenDB(name string) (kvdb.Store, error) {
37 | s, err := p.DBProducer.OpenDB(name)
38 | return &countedStore{s}, err
39 | }
40 |
41 | func (p *countedFullDbProducer) OpenDB(name string) (kvdb.Store, error) {
42 | s, err := p.FullDBProducer.OpenDB(name)
43 | return &countedStore{s}, err
44 | }
45 |
46 | var notifier = logger.New("threads-pool")
47 |
48 | func (s *countedStore) NewIterator(prefix []byte, start []byte) kvdb.Iterator {
49 | got, release := GlobalPool.Lock(1)
50 | if got < 1 {
51 | notifier.Log.Warn("Too many DB iterators")
52 | }
53 |
54 | return &countedIterator{
55 | Iterator: s.Store.NewIterator(prefix, start),
56 | release: release,
57 | }
58 | }
59 |
60 | func (it *countedIterator) Release() {
61 | it.Iterator.Release()
62 | it.release(1)
63 | }
64 |
--------------------------------------------------------------------------------
/utils/dbutil/threads/pool.go:
--------------------------------------------------------------------------------
1 | package threads
2 |
3 | import (
4 | "runtime/debug"
5 | "sync"
6 | )
7 |
8 | const GoroutinesPerThread = 0.8
9 |
10 | // threadPool counts threads in use
11 | type ThreadPool struct {
12 | mu sync.Mutex
13 | cap int
14 | left int
15 | }
16 |
17 | var GlobalPool ThreadPool
18 |
19 | // init ThreadPool only on demand to give time to other packages
20 | // call debug.SetMaxThreads() if they need
21 | func (p *ThreadPool) init() {
22 | if p.cap == 0 {
23 | p.cap = int(getMaxThreads() * GoroutinesPerThread)
24 | p.left = p.cap
25 | }
26 | }
27 |
28 | // Capacity of pool
29 | func (p *ThreadPool) Cap() int {
30 | if p.cap == 0 {
31 | p.mu.Lock()
32 | defer p.mu.Unlock()
33 | p.init()
34 | }
35 | return p.cap
36 | }
37 |
38 | func (p *ThreadPool) Lock(want int) (got int, release func(count int)) {
39 | p.mu.Lock()
40 | defer p.mu.Unlock()
41 |
42 | p.init()
43 |
44 | if want < 1 {
45 | want = 0
46 | }
47 |
48 | got = min(p.left, want)
49 | p.left -= got
50 |
51 | release = func(count int) {
52 | p.mu.Lock()
53 | defer p.mu.Unlock()
54 |
55 | if 0 > count || count > got {
56 | count = got
57 | }
58 |
59 | got -= count
60 | p.left += count
61 | }
62 |
63 | return
64 | }
65 |
66 | func getMaxThreads() float64 {
67 | was := debug.SetMaxThreads(10000)
68 | debug.SetMaxThreads(was)
69 | return float64(was)
70 | }
71 |
72 | func min(a, b int) int {
73 | if a < b {
74 | return a
75 | }
76 | return b
77 | }
78 |
--------------------------------------------------------------------------------
/utils/dbutil/threads/pool_test.go:
--------------------------------------------------------------------------------
1 | package threads
2 |
3 | import (
4 | "os"
5 | "runtime/debug"
6 | "testing"
7 |
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestMain(m *testing.M) {
12 | debug.SetMaxThreads(10)
13 |
14 | os.Exit(m.Run())
15 | }
16 |
17 | func TestThreadPool(t *testing.T) {
18 |
19 | for name, pool := range map[string]ThreadPool{
20 | "global": GlobalPool,
21 | "local": ThreadPool{},
22 | } {
23 | t.Run(name, func(t *testing.T) {
24 | require := require.New(t)
25 |
26 | require.Equal(8, pool.Cap())
27 |
28 | got, release := pool.Lock(0)
29 | require.Equal(0, got)
30 | release(1)
31 |
32 | gotA, releaseA := pool.Lock(10)
33 | require.Equal(8, gotA)
34 | releaseA(1)
35 |
36 | gotB, releaseB := pool.Lock(10)
37 | require.Equal(1, gotB)
38 | releaseB(gotB)
39 |
40 | releaseA(gotA)
41 | gotB, releaseB = pool.Lock(10)
42 | require.Equal(8, gotB)
43 |
44 | // don't releaseB(gotB) to check pools isolation
45 | })
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/utils/devnullfile/devnull.go:
--------------------------------------------------------------------------------
1 | package devnullfile
2 |
3 | type DevNull struct{}
4 |
5 | func (d DevNull) Read(pp []byte) (n int, err error) {
6 | for i := range pp {
7 | pp[i] = 0
8 | }
9 | return len(pp), nil
10 | }
11 |
12 | func (d DevNull) Write(pp []byte) (n int, err error) {
13 | return len(pp), nil
14 | }
15 |
16 | func (d DevNull) Close() error {
17 | return nil
18 | }
19 |
20 | func (d DevNull) Seek(offset int64, whence int) (int64, error) {
21 | return 0, nil
22 | }
23 |
24 | func (d DevNull) Drop() error {
25 | return nil
26 | }
27 |
--------------------------------------------------------------------------------
/utils/eventid/eventid.go:
--------------------------------------------------------------------------------
1 | package eventid
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/hash"
7 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
8 | )
9 |
10 | type Cache struct {
11 | ids map[hash.Event]bool
12 | mu sync.RWMutex
13 | maxSize int
14 | epoch idx.Epoch
15 | }
16 |
17 | func NewCache(maxSize int) *Cache {
18 | return &Cache{
19 | maxSize: maxSize,
20 | }
21 | }
22 |
23 | func (c *Cache) Reset(epoch idx.Epoch) {
24 | c.mu.Lock()
25 | defer c.mu.Unlock()
26 | c.ids = make(map[hash.Event]bool)
27 | c.epoch = epoch
28 | }
29 |
30 | func (c *Cache) Has(id hash.Event) (has bool, ok bool) {
31 | c.mu.RLock()
32 | defer c.mu.RUnlock()
33 |
34 | if c.ids == nil {
35 | return false, false
36 | }
37 | if c.epoch != id.Epoch() {
38 | return false, false
39 | }
40 | return c.ids[id], true
41 | }
42 |
43 | func (c *Cache) Add(id hash.Event) bool {
44 | c.mu.Lock()
45 | defer c.mu.Unlock()
46 |
47 | if c.ids == nil {
48 | return false
49 | }
50 | if c.epoch != id.Epoch() {
51 | return false
52 | }
53 | if len(c.ids) >= c.maxSize {
54 | c.ids = nil
55 | return false
56 | }
57 | c.ids[id] = true
58 | return true
59 | }
60 |
61 | func (c *Cache) Remove(id hash.Event) {
62 | c.mu.Lock()
63 | defer c.mu.Unlock()
64 |
65 | if c.ids == nil {
66 | return
67 | }
68 | delete(c.ids, id)
69 | }
70 |
--------------------------------------------------------------------------------
/utils/fast/buffer.go:
--------------------------------------------------------------------------------
1 | package fast
2 |
3 | type Reader struct {
4 | buf []byte
5 | offset int
6 | }
7 |
8 | type Writer struct {
9 | buf []byte
10 | }
11 |
12 | // NewReader wraps bytes with reading buffer.
13 | func NewReader(bb []byte) *Reader {
14 | return &Reader{
15 | buf: bb,
16 | offset: 0,
17 | }
18 | }
19 |
20 | // NewWriter wraps bytes with writing buffer.
21 | func NewWriter(bb []byte) *Writer {
22 | return &Writer{
23 | buf: bb,
24 | }
25 | }
26 |
27 | // WriteByte to the buffer.
28 | func (b *Writer) WriteByte(v byte) {
29 | b.buf = append(b.buf, v)
30 | }
31 |
32 | // Write the byte to the buffer.
33 | func (b *Writer) Write(v []byte) {
34 | b.buf = append(b.buf, v...)
35 | }
36 |
37 | // Read n bytes.
38 | func (b *Reader) Read(n int) []byte {
39 | var res []byte
40 | res = b.buf[b.offset : b.offset+n]
41 | b.offset += n
42 |
43 | return res
44 | }
45 |
46 | // ReadByte reads 1 byte.
47 | func (b *Reader) ReadByte() byte {
48 | var res byte
49 | res = b.buf[b.offset]
50 | b.offset++
51 |
52 | return res
53 | }
54 |
55 | // Position of internal cursor.
56 | func (b *Reader) Position() int {
57 | return b.offset
58 | }
59 |
60 | // Bytes of internal buffer
61 | func (b *Reader) Bytes() []byte {
62 | return b.buf
63 | }
64 |
65 | // Bytes of internal buffer
66 | func (b *Writer) Bytes() []byte {
67 | return b.buf
68 | }
69 |
70 | // Empty returns true if the whole buffer is consumed
71 | func (b *Reader) Empty() bool {
72 | return len(b.buf) == b.offset
73 | }
74 |
--------------------------------------------------------------------------------
/utils/file.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "io/ioutil"
5 | "os"
6 | "path/filepath"
7 |
8 | "github.com/ethereum/go-ethereum/log"
9 | )
10 |
11 | func OpenFile(path string, isSyncMode bool) *os.File {
12 | const dirPerm = 0700
13 | if err := os.MkdirAll(filepath.Dir(path), dirPerm); err != nil {
14 | log.Crit("Failed to create file dir", "file", path, "err", err)
15 | }
16 | sync := 0
17 | if isSyncMode {
18 | sync = os.O_SYNC
19 | }
20 | fh, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|sync, 0666)
21 | if err != nil {
22 | log.Crit("Failed to open file", "file", path, "err", err)
23 | }
24 | return fh
25 | }
26 |
27 | func FileExists(path string) bool {
28 | _, err := os.Stat(path)
29 | return err == nil
30 | }
31 |
32 | func FilePut(path string, content []byte, isSyncMode bool) {
33 | fh := OpenFile(path, isSyncMode)
34 | defer fh.Close()
35 | if err := fh.Truncate(0); err != nil {
36 | log.Crit("Failed to truncate file", "file", path, "err", err)
37 | }
38 | if _, err := fh.Write(content); err != nil {
39 | log.Crit("Failed to write to file", "file", path, "err", err)
40 | }
41 | }
42 |
43 | func FileGet(path string) []byte {
44 | if !FileExists(path) {
45 | return nil
46 | }
47 | fh, err := os.Open(path)
48 | if err != nil {
49 | log.Crit("Failed to open file", "file", path, "err", err)
50 | }
51 | defer fh.Close()
52 | res, _ := ioutil.ReadAll(fh)
53 | return res
54 | }
55 |
--------------------------------------------------------------------------------
/utils/ioread/ioread.go:
--------------------------------------------------------------------------------
1 | package ioread
2 |
3 | import "io"
4 |
5 | func ReadAll(reader io.Reader, buf []byte) error {
6 | consumed := 0
7 | for {
8 | n, err := reader.Read(buf[consumed:])
9 | consumed += n
10 | if consumed == len(buf) {
11 | return nil
12 | }
13 | if err != nil {
14 | return err
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/utils/memory/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2017, Jeremy Jay
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/utils/memory/doc.go:
--------------------------------------------------------------------------------
1 | // Package memory provides a single method reporting total system memory
2 | // accessible to the kernel.
3 | package memory
4 |
5 | // TotalMemory returns the total accessible system memory in bytes.
6 | //
7 | // The total accessible memory is installed physical memory size minus reserved
8 | // areas for the kernel and hardware, if such reservations are reported by
9 | // the operating system.
10 | //
11 | // If accessible memory size could not be determined, then 0 is returned.
12 | func TotalMemory() uint64 {
13 | return sysTotalMemory()
14 | }
15 |
16 | // FreeMemory returns the total free system memory in bytes.
17 | //
18 | // The total free memory is installed physical memory size minus reserved
19 | // areas for other applications running on the same system.
20 | //
21 | // If free memory size could not be determined, then 0 is returned.
22 | func FreeMemory() uint64 {
23 | return sysFreeMemory()
24 | }
25 |
--------------------------------------------------------------------------------
/utils/memory/memory_bsd.go:
--------------------------------------------------------------------------------
1 | //go:build freebsd || openbsd || dragonfly || netbsd
2 | // +build freebsd openbsd dragonfly netbsd
3 |
4 | package memory
5 |
6 | func sysTotalMemory() uint64 {
7 | s, err := sysctlUint64("hw.physmem")
8 | if err != nil {
9 | return 0
10 | }
11 | return s
12 | }
13 |
14 | func sysFreeMemory() uint64 {
15 | s, err := sysctlUint64("hw.usermem")
16 | if err != nil {
17 | return 0
18 | }
19 | return s
20 | }
21 |
--------------------------------------------------------------------------------
/utils/memory/memory_darwin.go:
--------------------------------------------------------------------------------
1 | //go:build darwin
2 | // +build darwin
3 |
4 | package memory
5 |
6 | import (
7 | "os/exec"
8 | "regexp"
9 | "strconv"
10 | )
11 |
12 | func sysTotalMemory() uint64 {
13 | s, err := sysctlUint64("hw.memsize")
14 | if err != nil {
15 | return 0
16 | }
17 | return s
18 | }
19 |
20 | func sysFreeMemory() uint64 {
21 | cmd := exec.Command("vm_stat")
22 | outBytes, err := cmd.Output()
23 | if err != nil {
24 | return 0
25 | }
26 |
27 | rePageSize := regexp.MustCompile("page size of ([0-9]*) bytes")
28 | reFreePages := regexp.MustCompile("Pages free: *([0-9]*)\\.")
29 |
30 | // default: page size of 4096 bytes
31 | matches := rePageSize.FindSubmatchIndex(outBytes)
32 | pageSize := uint64(4096)
33 | if len(matches) == 4 {
34 | pageSize, err = strconv.ParseUint(string(outBytes[matches[2]:matches[3]]), 10, 64)
35 | if err != nil {
36 | return 0
37 | }
38 | }
39 |
40 | // ex: Pages free: 1126961.
41 | matches = reFreePages.FindSubmatchIndex(outBytes)
42 | freePages := uint64(0)
43 | if len(matches) == 4 {
44 | freePages, err = strconv.ParseUint(string(outBytes[matches[2]:matches[3]]), 10, 64)
45 | if err != nil {
46 | return 0
47 | }
48 | }
49 | return freePages * pageSize
50 | }
51 |
--------------------------------------------------------------------------------
/utils/memory/memory_linux.go:
--------------------------------------------------------------------------------
1 | //go:build linux
2 | // +build linux
3 |
4 | package memory
5 |
6 | import "syscall"
7 |
8 | func sysTotalMemory() uint64 {
9 | in := &syscall.Sysinfo_t{}
10 | err := syscall.Sysinfo(in)
11 | if err != nil {
12 | return 0
13 | }
14 | // If this is a 32-bit system, then these fields are
15 | // uint32 instead of uint64.
16 | // So we always convert to uint64 to match signature.
17 | return uint64(in.Totalram) * uint64(in.Unit)
18 | }
19 |
20 | func sysFreeMemory() uint64 {
21 | in := &syscall.Sysinfo_t{}
22 | err := syscall.Sysinfo(in)
23 | if err != nil {
24 | return 0
25 | }
26 | // If this is a 32-bit system, then these fields are
27 | // uint32 instead of uint64.
28 | // So we always convert to uint64 to match signature.
29 | return uint64(in.Freeram) * uint64(in.Unit)
30 | }
31 |
--------------------------------------------------------------------------------
/utils/memory/memory_test.go:
--------------------------------------------------------------------------------
1 | package memory
2 |
3 | import "testing"
4 |
5 | func TestNonZero(t *testing.T) {
6 | if TotalMemory() == 0 {
7 | t.Fatal("TotalMemory returned 0")
8 | }
9 | if FreeMemory() == 0 {
10 | t.Fatal("FreeMemory returned 0")
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/utils/memory/memory_windows.go:
--------------------------------------------------------------------------------
1 | //go:build windows
2 | // +build windows
3 |
4 | package memory
5 |
6 | import (
7 | "syscall"
8 | "unsafe"
9 | )
10 |
11 | // omitting a few fields for brevity...
12 | // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366589(v=vs.85).aspx
13 | type memStatusEx struct {
14 | dwLength uint32
15 | dwMemoryLoad uint32
16 | ullTotalPhys uint64
17 | ullAvailPhys uint64
18 | unused [5]uint64
19 | }
20 |
21 | func sysTotalMemory() uint64 {
22 | kernel32, err := syscall.LoadDLL("kernel32.dll")
23 | if err != nil {
24 | return 0
25 | }
26 | // GetPhysicallyInstalledSystemMemory is simpler, but broken on
27 | // older versions of windows (and uses this under the hood anyway).
28 | globalMemoryStatusEx, err := kernel32.FindProc("GlobalMemoryStatusEx")
29 | if err != nil {
30 | return 0
31 | }
32 | msx := &memStatusEx{
33 | dwLength: 64,
34 | }
35 | r, _, _ := globalMemoryStatusEx.Call(uintptr(unsafe.Pointer(msx)))
36 | if r == 0 {
37 | return 0
38 | }
39 | return msx.ullTotalPhys
40 | }
41 |
42 | func sysFreeMemory() uint64 {
43 | kernel32, err := syscall.LoadDLL("kernel32.dll")
44 | if err != nil {
45 | return 0
46 | }
47 | // GetPhysicallyInstalledSystemMemory is simpler, but broken on
48 | // older versions of windows (and uses this under the hood anyway).
49 | globalMemoryStatusEx, err := kernel32.FindProc("GlobalMemoryStatusEx")
50 | if err != nil {
51 | return 0
52 | }
53 | msx := &memStatusEx{
54 | dwLength: 64,
55 | }
56 | r, _, _ := globalMemoryStatusEx.Call(uintptr(unsafe.Pointer(msx)))
57 | if r == 0 {
58 | return 0
59 | }
60 | return msx.ullAvailPhys
61 | }
62 |
--------------------------------------------------------------------------------
/utils/memory/memsysctl.go:
--------------------------------------------------------------------------------
1 | //go:build darwin || freebsd || openbsd || dragonfly || netbsd
2 | // +build darwin freebsd openbsd dragonfly netbsd
3 |
4 | package memory
5 |
6 | import (
7 | "syscall"
8 | "unsafe"
9 | )
10 |
11 | func sysctlUint64(name string) (uint64, error) {
12 | s, err := syscall.Sysctl(name)
13 | if err != nil {
14 | return 0, err
15 | }
16 | // hack because the string conversion above drops a \0
17 | b := []byte(s)
18 | if len(b) < 8 {
19 | b = append(b, 0)
20 | }
21 | return *(*uint64)(unsafe.Pointer(&b[0])), nil
22 | }
23 |
--------------------------------------------------------------------------------
/utils/memory/stub.go:
--------------------------------------------------------------------------------
1 | //go:build !linux && !darwin && !windows && !freebsd && !dragonfly && !netbsd && !openbsd
2 | // +build !linux,!darwin,!windows,!freebsd,!dragonfly,!netbsd,!openbsd
3 |
4 | package memory
5 |
6 | func sysTotalMemory() uint64 {
7 | return 0
8 | }
9 | func sysFreeMemory() uint64 {
10 | return 0
11 | }
12 |
--------------------------------------------------------------------------------
/utils/migration/id_store.go:
--------------------------------------------------------------------------------
1 | package migration
2 |
3 | // IDStore interface for stores id in migrations
4 | type IDStore interface {
5 | GetID() string
6 | SetID(string)
7 | }
8 |
9 | type inmemIDStore struct {
10 | lastID string
11 | }
12 |
13 | func (p *inmemIDStore) GetID() string {
14 | return string(p.lastID)
15 | }
16 |
17 | func (p *inmemIDStore) SetID(id string) {
18 | p.lastID = id
19 | }
20 |
--------------------------------------------------------------------------------
/utils/migration/kvdb_id_store.go:
--------------------------------------------------------------------------------
1 | package migration
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/kvdb"
5 | "github.com/ethereum/go-ethereum/log"
6 | )
7 |
8 | // KvdbIDStore stores id
9 | type KvdbIDStore struct {
10 | table kvdb.Store
11 | key []byte
12 | }
13 |
14 | // NewKvdbIDStore constructor
15 | func NewKvdbIDStore(table kvdb.Store) *KvdbIDStore {
16 | return &KvdbIDStore{
17 | table: table,
18 | key: []byte("id"),
19 | }
20 | }
21 |
22 | // GetID is a getter
23 | func (p *KvdbIDStore) GetID() string {
24 | id, err := p.table.Get(p.key)
25 | if err != nil {
26 | log.Crit("Failed to get key-value", "err", err)
27 | }
28 |
29 | if id == nil {
30 | return ""
31 | }
32 | return string(id)
33 | }
34 |
35 | // SetID is a setter
36 | func (p *KvdbIDStore) SetID(id string) {
37 | err := p.table.Put(p.key, []byte(id))
38 | if err != nil {
39 | log.Crit("Failed to put key-value", "err", err)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/utils/nameof.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/hash"
7 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
8 | )
9 |
10 | // NameOf returns human readable string representation.
11 | func NameOf(p idx.ValidatorID) string {
12 | if name := hash.GetNodeName(p); len(name) > 0 {
13 | return name
14 | }
15 |
16 | return fmt.Sprintf("%d", p)
17 | }
18 |
--------------------------------------------------------------------------------
/utils/num_queue.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "sync"
5 | )
6 |
7 | type NumQueue struct {
8 | mu sync.Mutex
9 | lastDone uint64
10 | waiters []chan struct{}
11 | }
12 |
13 | func NewNumQueue(init uint64) *NumQueue {
14 | return &NumQueue{
15 | lastDone: init,
16 | }
17 | }
18 |
19 | func (q *NumQueue) Done(n uint64) {
20 | q.mu.Lock()
21 | defer q.mu.Unlock()
22 |
23 | if n <= q.lastDone {
24 | panic("Already done!")
25 | }
26 |
27 | pos := int(n - q.lastDone - 1)
28 | for i := 0; i < len(q.waiters) && i <= pos; i++ {
29 | close(q.waiters[i])
30 | }
31 | if pos < len(q.waiters) {
32 | q.waiters = q.waiters[pos+1:]
33 | } else {
34 | q.waiters = make([]chan struct{}, 0, 1000)
35 | }
36 |
37 | q.lastDone = n
38 | }
39 |
40 | func (q *NumQueue) WaitFor(n uint64) {
41 | q.mu.Lock()
42 |
43 | if n <= q.lastDone {
44 | q.mu.Unlock()
45 | return
46 | }
47 |
48 | count := int(n - q.lastDone)
49 | for i := len(q.waiters); i < count; i++ {
50 | q.waiters = append(q.waiters, make(chan struct{}))
51 | }
52 | ch := q.waiters[count-1]
53 | q.mu.Unlock()
54 | <-ch
55 | }
56 |
--------------------------------------------------------------------------------
/utils/num_queue_test.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "math/rand"
5 | "sync"
6 | "testing"
7 |
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestNumQueue(t *testing.T) {
12 |
13 | t.Run("Simple", func(t *testing.T) {
14 | N := uint64(100)
15 | q := NewNumQueue(0)
16 | for i := uint64(1); i <= N; i++ {
17 | var iter sync.WaitGroup
18 | iter.Add(1)
19 | go func(i uint64) {
20 | defer iter.Done()
21 | q.WaitFor(i)
22 | }(i)
23 |
24 | q.Done(i)
25 | iter.Wait()
26 | }
27 | })
28 |
29 | t.Run("Random", func(t *testing.T) {
30 | require := require.New(t)
31 | N := 100
32 |
33 | q := NewNumQueue(0)
34 | output := make(chan uint64, 10)
35 | nums := rand.Perm(N)
36 |
37 | for _, n := range nums {
38 | go func(n uint64) {
39 | q.WaitFor(n - 1)
40 | output <- n
41 | if n == uint64(N) {
42 | close(output)
43 | }
44 | q.Done(n)
45 |
46 | }(uint64(n + 1))
47 | }
48 |
49 | var prev uint64
50 | for got := range output {
51 | require.Less(prev, got)
52 | prev = got
53 | }
54 | })
55 | }
56 |
--------------------------------------------------------------------------------
/utils/pretty_duration.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 | "time"
6 |
7 | "github.com/ethereum/go-ethereum/common"
8 | )
9 |
10 | // PrettyDuration is a combination of common.PrettyDuration and common.PrettyAge
11 | // It is a pretty printed version of a time.Duration value that rounds
12 | // the values up to a single most significant unit,
13 | // while showing the least significant part if duration isn't too large.
14 | type PrettyDuration time.Duration
15 |
16 | // ageUnits is a list of units the age pretty printing uses.
17 | var ageUnits = []struct {
18 | Size time.Duration
19 | Symbol string
20 | }{
21 | {12 * 30 * 24 * time.Hour, "y"},
22 | {30 * 24 * time.Hour, "mo"},
23 | {24 * time.Hour, "d"},
24 | {time.Hour, "h"},
25 | {time.Minute, "m"},
26 | }
27 |
28 | // String implements the Stringer interface, allowing pretty printing of duration
29 | // values rounded to the most significant time unit.
30 | func (t PrettyDuration) String() string {
31 | // Calculate the time difference and handle the 0 cornercase
32 | diff := time.Duration(t)
33 | // Accumulate a precision of 3 components before returning
34 | result, prec := "", 0
35 | if diff < 0 {
36 | diff = -diff
37 | result = "-"
38 | }
39 |
40 | for _, unit := range ageUnits {
41 | if diff > unit.Size {
42 | result = fmt.Sprintf("%s%d%s", result, diff/unit.Size, unit.Symbol)
43 | diff %= unit.Size
44 |
45 | if prec += 1; prec >= 3 {
46 | break
47 | }
48 | }
49 | }
50 | if prec < 3 {
51 | return fmt.Sprintf("%s%s", result, common.PrettyDuration(diff).String())
52 | }
53 | return result
54 | }
55 |
--------------------------------------------------------------------------------
/utils/pretty_duration_test.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestPrettyDuration_String(t *testing.T) {
11 | for _, testcase := range []struct {
12 | str string
13 | val time.Duration
14 | }{
15 | {"0s", 0},
16 | {"1ns", time.Nanosecond},
17 | {"1µs", time.Microsecond},
18 | {"1ms", time.Millisecond},
19 | {"1s", time.Second},
20 | {"1.000s", time.Second + time.Microsecond + time.Nanosecond},
21 | {"1.001s", time.Second + time.Millisecond + time.Microsecond + time.Nanosecond},
22 | {"1m1.001s", time.Minute + time.Second + time.Millisecond + time.Microsecond + time.Nanosecond},
23 | {"1h1m1.001s", time.Hour + time.Minute + time.Second + time.Millisecond + time.Microsecond + time.Nanosecond},
24 | {"1d1h1m", 24*time.Hour + time.Hour + time.Minute + time.Second + time.Millisecond + time.Microsecond + time.Nanosecond},
25 | {"1mo1d1h", 30*24*time.Hour + 24*time.Hour + time.Hour + time.Minute + time.Second + time.Millisecond + time.Microsecond + time.Nanosecond},
26 | {"26y4mo23d", time.Duration(9503.123456789 * 24 * float64(time.Hour))},
27 | } {
28 | require.Equal(t, testcase.str, PrettyDuration(testcase.val).String())
29 | if testcase.val > 0 {
30 | require.Equal(t, "-"+testcase.str, PrettyDuration(-testcase.val).String())
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/utils/randat/rand_at.go:
--------------------------------------------------------------------------------
1 | package randat
2 |
3 | import (
4 | "math/rand"
5 | )
6 |
7 | type cached struct {
8 | seed uint64
9 | r uint64
10 | }
11 |
12 | var (
13 | gSeed = rand.Int63()
14 | cache = cached{}
15 | )
16 |
17 | // RandAt returns random number with seed
18 | // Not safe for concurrent use
19 | func RandAt(seed uint64) uint64 {
20 | if seed != 0 && cache.seed == seed {
21 | return cache.r
22 | }
23 | cache.seed = seed
24 | cache.r = rand.New(rand.NewSource(gSeed ^ int64(seed))).Uint64()
25 | return cache.r
26 | }
27 |
--------------------------------------------------------------------------------
/utils/rate/gauge_test.go:
--------------------------------------------------------------------------------
1 | package rate
2 |
3 | import (
4 | "sync"
5 | "testing"
6 | )
7 |
8 | func TestGauge_Concurrency(t *testing.T) {
9 | for try := 0; try < 100; try++ {
10 | testGaugeConcurrency(t)
11 | }
12 | }
13 |
14 | func testGaugeConcurrency(t *testing.T) {
15 | g := NewGauge()
16 | barrier := make(chan struct{})
17 | wg := sync.WaitGroup{}
18 | end := int64(32)
19 | for i := int64(0); i <= end; i++ {
20 | wg.Add(1)
21 | turn := i
22 | go func() {
23 | defer wg.Done()
24 | select {
25 | case <-barrier:
26 | g.Mark(turn)
27 | if v := int64(g.rateToGauge(float64(2*end), 1)); v < turn {
28 | t.Errorf("%d >= %d", v, end)
29 | }
30 | return
31 | }
32 | }()
33 | }
34 | close(barrier)
35 | wg.Wait()
36 | if v := int64(g.rateToGauge(float64(2*end), 1)); v != end {
37 | t.Errorf("%d != %d", v, end)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/utils/rlpstore/rlpstore.go:
--------------------------------------------------------------------------------
1 | package rlpstore
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/logger"
5 | "github.com/Fantom-foundation/lachesis-base/kvdb"
6 | "github.com/ethereum/go-ethereum/rlp"
7 | )
8 |
9 | type Helper struct {
10 | logger.Instance
11 | }
12 |
13 | // Set RLP value
14 | func (s *Helper) Set(table kvdb.Store, key []byte, val interface{}) {
15 | buf, err := rlp.EncodeToBytes(val)
16 | if err != nil {
17 | s.Log.Crit("Failed to encode rlp", "err", err)
18 | }
19 |
20 | if err := table.Put(key, buf); err != nil {
21 | s.Log.Crit("Failed to put key-value", "err", err)
22 | }
23 | }
24 |
25 | // Get RLP value
26 | func (s *Helper) Get(table kvdb.Store, key []byte, to interface{}) interface{} {
27 | buf, err := table.Get(key)
28 | if err != nil {
29 | s.Log.Crit("Failed to get key-value", "err", err)
30 | }
31 | if buf == nil {
32 | return nil
33 | }
34 |
35 | err = rlp.DecodeBytes(buf, to)
36 | if err != nil {
37 | s.Log.Crit("Failed to decode rlp", "err", err, "size", len(buf))
38 | }
39 | return to
40 | }
41 |
--------------------------------------------------------------------------------
/utils/self-table.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/kvdb"
5 | "github.com/Fantom-foundation/lachesis-base/kvdb/table"
6 | )
7 |
8 | func NewTableOrSelf(db kvdb.Store, prefix []byte) kvdb.Store {
9 | if len(prefix) == 0 {
10 | return db
11 | }
12 | return table.New(db, prefix)
13 | }
14 |
--------------------------------------------------------------------------------
/utils/signers/gsignercache/global_cache.go:
--------------------------------------------------------------------------------
1 | package gsignercache
2 |
3 | import (
4 | "github.com/ethereum/go-ethereum/common"
5 | "github.com/ethereum/go-ethereum/core/types"
6 | lru "github.com/hashicorp/golang-lru"
7 | )
8 |
9 | var (
10 | globalCache, _ = lru.New(40000)
11 | )
12 |
13 | type WlruCache struct {
14 | Cache *lru.Cache
15 | }
16 |
17 | func (w *WlruCache) Add(txid common.Hash, c types.CachedSender) {
18 | w.Cache.Add(txid, c)
19 | }
20 |
21 | func (w *WlruCache) Get(txid common.Hash) *types.CachedSender {
22 | ic, ok := w.Cache.Get(txid)
23 | if !ok {
24 | return nil
25 | }
26 | c := ic.(types.CachedSender)
27 | return &c
28 | }
29 |
30 | func Wrap(signer types.Signer) types.Signer {
31 | return types.WrapWithCachedSigner(signer, &WlruCache{globalCache})
32 | }
33 |
--------------------------------------------------------------------------------
/utils/signers/internaltx/internaltx.go:
--------------------------------------------------------------------------------
1 | package internaltx
2 |
3 | import (
4 | "github.com/ethereum/go-ethereum/common"
5 | "github.com/ethereum/go-ethereum/core/types"
6 | )
7 |
8 | func IsInternal(tx *types.Transaction) bool {
9 | v, r, _ := tx.RawSignatureValues()
10 | return v.Sign() == 0 && r.Sign() == 0
11 | }
12 |
13 | func InternalSender(tx *types.Transaction) common.Address {
14 | _, _, s := tx.RawSignatureValues()
15 | return common.BytesToAddress(s.Bytes())
16 | }
17 |
18 | func Sender(signer types.Signer, tx *types.Transaction) (common.Address, error) {
19 | if !IsInternal(tx) {
20 | return types.Sender(signer, tx)
21 | }
22 | return InternalSender(tx), nil
23 | }
24 |
--------------------------------------------------------------------------------
/utils/spin_lock.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "runtime"
5 | "sync/atomic"
6 | )
7 |
8 | // SpinLock implements a simple atomic spin lock, the zero value for a SpinLock is an unlocked spinlock.
9 | type SpinLock struct {
10 | f uint32
11 | }
12 |
13 | // Lock locks sl. If the lock is already in use, the caller blocks until Unlock is called
14 | func (sl *SpinLock) Lock() {
15 | for !sl.TryLock() {
16 | runtime.Gosched() // allow other goroutines to do work.
17 | }
18 | }
19 |
20 | // Unlock unlocks sl, unlike [Mutex.Unlock](http://golang.org/pkg/sync/#Mutex.Unlock),
21 | // there's no harm calling it on an unlocked SpinLock
22 | func (sl *SpinLock) Unlock() {
23 | atomic.StoreUint32(&sl.f, 0)
24 | }
25 |
26 | // TryLock will try to lock sl and return whether it succeed or not without blocking.
27 | func (sl *SpinLock) TryLock() bool {
28 | return atomic.CompareAndSwapUint32(&sl.f, 0, 1)
29 | }
30 |
31 | // String is human readable lock state
32 | func (sl *SpinLock) String() string {
33 | if atomic.LoadUint32(&sl.f) == 1 {
34 | return "Locked"
35 | }
36 | return "Unlocked"
37 | }
38 |
--------------------------------------------------------------------------------
/utils/to_ftm.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import "math/big"
4 |
5 | // ToFtm number of FTM to Wei
6 | func ToFtm(ftm uint64) *big.Int {
7 | return new(big.Int).Mul(new(big.Int).SetUint64(ftm), big.NewInt(1e18))
8 | }
9 |
--------------------------------------------------------------------------------
/utils/txtime/txtime.go:
--------------------------------------------------------------------------------
1 | package txtime
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/utils/wlru"
7 | "github.com/ethereum/go-ethereum/common"
8 | )
9 |
10 | var (
11 | globalFinalized, _ = wlru.New(30000, 30000)
12 | globalNonFinalized, _ = wlru.New(5000, 5000)
13 | Enabled = false
14 | )
15 |
16 | func Saw(txid common.Hash, t time.Time) {
17 | if !Enabled {
18 | return
19 | }
20 | globalNonFinalized.ContainsOrAdd(txid, t, 1)
21 | }
22 |
23 | func Validated(txid common.Hash, t time.Time) {
24 | if !Enabled {
25 | return
26 | }
27 | v, has := globalNonFinalized.Peek(txid)
28 | if has {
29 | t = v.(time.Time)
30 | }
31 | globalFinalized.ContainsOrAdd(txid, t, 1)
32 | }
33 |
34 | func Of(txid common.Hash) time.Time {
35 | if !Enabled {
36 | return time.Time{}
37 | }
38 | v, has := globalFinalized.Get(txid)
39 | if has {
40 | return v.(time.Time)
41 | }
42 | v, has = globalNonFinalized.Get(txid)
43 | if has {
44 | return v.(time.Time)
45 | }
46 | now := time.Now()
47 | Saw(txid, now)
48 | return now
49 | }
50 |
--------------------------------------------------------------------------------
/utils/uint2hash.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "math/big"
5 |
6 | "github.com/ethereum/go-ethereum/common"
7 | )
8 |
9 | // BigTo256 converts big number to 32 bytes array
10 | func BigTo256(b *big.Int) common.Hash {
11 | return common.BytesToHash(b.Bytes())
12 | }
13 |
14 | // U64to256 converts uint64 to 32 bytes array
15 | func U64to256(u64 uint64) common.Hash {
16 | return BigTo256(new(big.Int).SetUint64(u64))
17 | }
18 |
19 | // U64toBig converts uint64 to big number
20 | func U64toBig(u64 uint64) *big.Int {
21 | return new(big.Int).SetUint64(u64)
22 | }
23 |
24 | // I64to256 converts int64 to 32 bytes array
25 | func I64to256(i64 int64) common.Hash {
26 | return BigTo256(new(big.Int).SetInt64(i64))
27 | }
28 |
--------------------------------------------------------------------------------
/utils/wgmutex/wg_mutex.go:
--------------------------------------------------------------------------------
1 | package wgmutex
2 |
3 | import "sync"
4 |
5 | type WgMutex struct {
6 | *sync.RWMutex
7 | wg *sync.WaitGroup
8 | }
9 |
10 | func New(m *sync.RWMutex, wg *sync.WaitGroup) *WgMutex {
11 | return &WgMutex{
12 | RWMutex: m,
13 | wg: wg,
14 | }
15 | }
16 |
17 | func (m *WgMutex) Lock() {
18 | m.RWMutex.Lock()
19 | m.wg.Wait()
20 | }
21 |
22 | func (m *WgMutex) RLock() {
23 | m.RWMutex.RLock()
24 | m.wg.Wait()
25 | }
26 |
--------------------------------------------------------------------------------
/valkeystore/cache.go:
--------------------------------------------------------------------------------
1 | package valkeystore
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/Fantom-foundation/go-opera/inter/validatorpk"
7 | "github.com/Fantom-foundation/go-opera/valkeystore/encryption"
8 | )
9 |
10 | var (
11 | ErrAlreadyUnlocked = errors.New("already unlocked")
12 | ErrLocked = errors.New("key is locked")
13 | )
14 |
15 | type CachedKeystore struct {
16 | backend RawKeystoreI
17 | cache map[string]*encryption.PrivateKey
18 | }
19 |
20 | func NewCachedKeystore(backend RawKeystoreI) *CachedKeystore {
21 | return &CachedKeystore{
22 | backend: backend,
23 | cache: make(map[string]*encryption.PrivateKey),
24 | }
25 | }
26 |
27 | func (c *CachedKeystore) Unlocked(pubkey validatorpk.PubKey) bool {
28 | _, ok := c.cache[c.idxOf(pubkey)]
29 | return ok
30 | }
31 |
32 | func (c *CachedKeystore) Has(pubkey validatorpk.PubKey) bool {
33 | if c.Unlocked(pubkey) {
34 | return true
35 | }
36 | return c.backend.Has(pubkey)
37 | }
38 |
39 | func (c *CachedKeystore) Unlock(pubkey validatorpk.PubKey, auth string) error {
40 | if c.Unlocked(pubkey) {
41 | return ErrAlreadyUnlocked
42 | }
43 | key, err := c.backend.Get(pubkey, auth)
44 | if err != nil {
45 | return err
46 | }
47 | c.cache[c.idxOf(pubkey)] = key
48 | return nil
49 | }
50 |
51 | func (c *CachedKeystore) GetUnlocked(pubkey validatorpk.PubKey) (*encryption.PrivateKey, error) {
52 | if !c.Unlocked(pubkey) {
53 | return nil, ErrLocked
54 | }
55 | return c.cache[c.idxOf(pubkey)], nil
56 | }
57 |
58 | func (c *CachedKeystore) idxOf(pubkey validatorpk.PubKey) string {
59 | return string(pubkey.Bytes())
60 | }
61 |
62 | func (c *CachedKeystore) Add(pubkey validatorpk.PubKey, key []byte, auth string) error {
63 | return c.backend.Add(pubkey, key, auth)
64 | }
65 |
66 | func (c *CachedKeystore) Get(pubkey validatorpk.PubKey, auth string) (*encryption.PrivateKey, error) {
67 | return c.backend.Get(pubkey, auth)
68 | }
69 |
--------------------------------------------------------------------------------
/valkeystore/default.go:
--------------------------------------------------------------------------------
1 | package valkeystore
2 |
3 | import (
4 | "github.com/ethereum/go-ethereum/accounts/keystore"
5 |
6 | "github.com/Fantom-foundation/go-opera/valkeystore/encryption"
7 | )
8 |
9 | func NewDefaultFileRawKeystore(dir string) *FileKeystore {
10 | enc := encryption.New(keystore.StandardScryptN, keystore.StandardScryptP)
11 | return NewFileKeystore(dir, enc)
12 | }
13 |
14 | func NewDefaultMemKeystore() *SyncedKeystore {
15 | return NewSyncedKeystore(NewCachedKeystore(NewMemKeystore()))
16 | }
17 |
18 | func NewDefaultFileKeystore(dir string) *SyncedKeystore {
19 | return NewSyncedKeystore(NewCachedKeystore(NewDefaultFileRawKeystore(dir)))
20 | }
21 |
--------------------------------------------------------------------------------
/valkeystore/encryption/io.go:
--------------------------------------------------------------------------------
1 | package encryption
2 |
3 | import (
4 | "io/ioutil"
5 | "os"
6 | "path/filepath"
7 | )
8 |
9 | func writeTemporaryKeyFile(file string, content []byte) (string, error) {
10 | // Create the keystore directory with appropriate permissions
11 | // in case it is not present yet.
12 | const dirPerm = 0700
13 | if err := os.MkdirAll(filepath.Dir(file), dirPerm); err != nil {
14 | return "", err
15 | }
16 | // Atomic write: create a temporary hidden file first
17 | // then move it into place. TempFile assigns mode 0600.
18 | f, err := ioutil.TempFile(filepath.Dir(file), "."+filepath.Base(file[0:16])+".tmp")
19 | if err != nil {
20 | return "", err
21 | }
22 | if _, err := f.Write(content); err != nil {
23 | f.Close()
24 | os.Remove(f.Name())
25 | return "", err
26 | }
27 | f.Close()
28 | return f.Name(), nil
29 | }
30 |
--------------------------------------------------------------------------------
/valkeystore/encryption/migration.go:
--------------------------------------------------------------------------------
1 | package encryption
2 |
3 | import (
4 | "encoding/json"
5 | "io/ioutil"
6 | "os"
7 |
8 | "github.com/ethereum/go-ethereum/accounts/keystore"
9 | "github.com/ethereum/go-ethereum/common"
10 |
11 | "github.com/Fantom-foundation/go-opera/inter/validatorpk"
12 | )
13 |
14 | type encryptedAccountKeyJSONV3 struct {
15 | Address string `json:"address"`
16 | Crypto keystore.CryptoJSON `json:"crypto"`
17 | Id string `json:"id"`
18 | Version int `json:"version"`
19 | }
20 |
21 | func MigrateAccountToValidatorKey(acckeypath string, valkeypath string, pubkey validatorpk.PubKey) error {
22 | acckeyjson, err := ioutil.ReadFile(acckeypath)
23 | if err != nil {
24 | return err
25 | }
26 | acck := new(encryptedAccountKeyJSONV3)
27 | if err := json.Unmarshal(acckeyjson, acck); err != nil {
28 | return err
29 | }
30 |
31 | valk := EncryptedKeyJSON{
32 | Type: validatorpk.Types.Secp256k1,
33 | PublicKey: common.Bytes2Hex(pubkey.Raw),
34 | Crypto: acck.Crypto,
35 | }
36 | valkeyjson, err := json.Marshal(valk)
37 | if err != nil {
38 | return err
39 | }
40 | tmpName, err := writeTemporaryKeyFile(valkeypath, valkeyjson)
41 | if err != nil {
42 | return err
43 | }
44 | return os.Rename(tmpName, valkeypath)
45 | }
46 |
--------------------------------------------------------------------------------
/valkeystore/files.go:
--------------------------------------------------------------------------------
1 | package valkeystore
2 |
3 | import (
4 | "errors"
5 | "os"
6 | "path"
7 |
8 | "github.com/ethereum/go-ethereum/common"
9 |
10 | "github.com/Fantom-foundation/go-opera/inter/validatorpk"
11 | "github.com/Fantom-foundation/go-opera/valkeystore/encryption"
12 | )
13 |
14 | var (
15 | ErrNotFound = errors.New("key is not found")
16 | ErrAlreadyExists = errors.New("key already exists")
17 | )
18 |
19 | type FileKeystore struct {
20 | enc *encryption.Keystore
21 | dir string
22 | }
23 |
24 | func NewFileKeystore(dir string, enc *encryption.Keystore) *FileKeystore {
25 | return &FileKeystore{
26 | enc: enc,
27 | dir: dir,
28 | }
29 | }
30 |
31 | func (f *FileKeystore) Has(pubkey validatorpk.PubKey) bool {
32 | return fileExists(f.PathOf(pubkey))
33 | }
34 |
35 | func (f *FileKeystore) Add(pubkey validatorpk.PubKey, key []byte, auth string) error {
36 | if f.Has(pubkey) {
37 | return ErrAlreadyExists
38 | }
39 | return f.enc.StoreKey(f.PathOf(pubkey), pubkey, key, auth)
40 | }
41 |
42 | func (f *FileKeystore) Get(pubkey validatorpk.PubKey, auth string) (*encryption.PrivateKey, error) {
43 | if !f.Has(pubkey) {
44 | return nil, ErrNotFound
45 | }
46 | return f.enc.ReadKey(pubkey, f.PathOf(pubkey), auth)
47 | }
48 |
49 | func (f *FileKeystore) PathOf(pubkey validatorpk.PubKey) string {
50 | return path.Join(f.dir, common.Bytes2Hex(pubkey.Bytes()))
51 | }
52 |
53 | func fileExists(filename string) bool {
54 | info, err := os.Stat(filename)
55 | if err != nil {
56 | return false
57 | }
58 | return !info.IsDir()
59 | }
60 |
--------------------------------------------------------------------------------
/valkeystore/keystore.go:
--------------------------------------------------------------------------------
1 | package valkeystore
2 |
3 | import (
4 | "github.com/Fantom-foundation/go-opera/inter/validatorpk"
5 | "github.com/Fantom-foundation/go-opera/valkeystore/encryption"
6 | )
7 |
8 | type RawKeystoreI interface {
9 | Has(pubkey validatorpk.PubKey) bool
10 | Add(pubkey validatorpk.PubKey, key []byte, auth string) error
11 | Get(pubkey validatorpk.PubKey, auth string) (*encryption.PrivateKey, error)
12 | }
13 |
14 | type KeystoreI interface {
15 | RawKeystoreI
16 | Unlock(pubkey validatorpk.PubKey, auth string) error
17 | Unlocked(pubkey validatorpk.PubKey) bool
18 | GetUnlocked(pubkey validatorpk.PubKey) (*encryption.PrivateKey, error)
19 | }
20 |
--------------------------------------------------------------------------------
/valkeystore/mem.go:
--------------------------------------------------------------------------------
1 | package valkeystore
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/ethereum/go-ethereum/crypto"
7 |
8 | "github.com/Fantom-foundation/go-opera/inter/validatorpk"
9 | "github.com/Fantom-foundation/go-opera/valkeystore/encryption"
10 | )
11 |
12 | type MemKeystore struct {
13 | mem map[string]*encryption.PrivateKey
14 | auth map[string]string
15 | }
16 |
17 | func NewMemKeystore() *MemKeystore {
18 | return &MemKeystore{
19 | mem: make(map[string]*encryption.PrivateKey),
20 | auth: make(map[string]string),
21 | }
22 | }
23 |
24 | func (m *MemKeystore) Has(pubkey validatorpk.PubKey) bool {
25 | _, ok := m.mem[m.idxOf(pubkey)]
26 | return ok
27 | }
28 |
29 | func (m *MemKeystore) Add(pubkey validatorpk.PubKey, key []byte, auth string) error {
30 | if m.Has(pubkey) {
31 | return ErrAlreadyExists
32 | }
33 | if pubkey.Type != validatorpk.Types.Secp256k1 {
34 | return encryption.ErrNotSupportedType
35 | }
36 | decoded, err := crypto.ToECDSA(key)
37 | if err != nil {
38 | return err
39 | }
40 | m.mem[m.idxOf(pubkey)] = &encryption.PrivateKey{
41 | Type: pubkey.Type,
42 | Bytes: key,
43 | Decoded: decoded,
44 | }
45 | m.auth[m.idxOf(pubkey)] = auth
46 | return nil
47 | }
48 |
49 | func (m *MemKeystore) Get(pubkey validatorpk.PubKey, auth string) (*encryption.PrivateKey, error) {
50 | if !m.Has(pubkey) {
51 | return nil, ErrNotFound
52 | }
53 | if m.auth[m.idxOf(pubkey)] != auth {
54 | return nil, errors.New("could not decrypt key with given password")
55 | }
56 | return m.mem[m.idxOf(pubkey)], nil
57 | }
58 |
59 | func (m *MemKeystore) idxOf(pubkey validatorpk.PubKey) string {
60 | return string(pubkey.Bytes())
61 | }
62 |
--------------------------------------------------------------------------------
/valkeystore/mem_test.go:
--------------------------------------------------------------------------------
1 | package valkeystore
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestMemKeystoreAdd(t *testing.T) {
10 | require := require.New(t)
11 | keystore := NewMemKeystore()
12 |
13 | key, err := keystore.Get(pubkey1, "auth1")
14 | require.EqualError(err, ErrNotFound.Error())
15 | require.Nil(key)
16 |
17 | err = keystore.Add(pubkey1, key1, "auth1")
18 | require.NoError(err)
19 |
20 | testGet(t, keystore, pubkey1, key1, "auth1")
21 |
22 | err = keystore.Add(pubkey2, key2, "auth2")
23 | require.NoError(err)
24 |
25 | testGet(t, keystore, pubkey1, key1, "auth1")
26 | testGet(t, keystore, pubkey2, key2, "auth2")
27 |
28 | err = keystore.Add(pubkey2, key2, "auth1")
29 | require.Error(err, ErrAlreadyExists.Error())
30 |
31 | testGet(t, keystore, pubkey2, key2, "auth2")
32 | }
33 |
--------------------------------------------------------------------------------
/valkeystore/signer.go:
--------------------------------------------------------------------------------
1 | package valkeystore
2 |
3 | import (
4 | "crypto/ecdsa"
5 |
6 | "github.com/ethereum/go-ethereum/crypto"
7 |
8 | "github.com/Fantom-foundation/go-opera/inter/validatorpk"
9 | "github.com/Fantom-foundation/go-opera/valkeystore/encryption"
10 | )
11 |
12 | type SignerI interface {
13 | Sign(pubkey validatorpk.PubKey, digest []byte) ([]byte, error)
14 | }
15 |
16 | type Signer struct {
17 | backend KeystoreI
18 | }
19 |
20 | func NewSigner(backend KeystoreI) *Signer {
21 | return &Signer{
22 | backend: backend,
23 | }
24 | }
25 |
26 | func (s *Signer) Sign(pubkey validatorpk.PubKey, digest []byte) ([]byte, error) {
27 | if pubkey.Type != validatorpk.Types.Secp256k1 {
28 | return nil, encryption.ErrNotSupportedType
29 | }
30 | key, err := s.backend.GetUnlocked(pubkey)
31 | if err != nil {
32 | return nil, err
33 | }
34 |
35 | secp256k1Key := key.Decoded.(*ecdsa.PrivateKey)
36 |
37 | sigRSV, err := crypto.Sign(digest, secp256k1Key)
38 | if err != nil {
39 | return nil, err
40 | }
41 | sigRS := sigRSV[:64]
42 | return sigRS, err
43 | }
44 |
--------------------------------------------------------------------------------
/valkeystore/sync.go:
--------------------------------------------------------------------------------
1 | package valkeystore
2 |
3 | import (
4 | "sync"
5 |
6 | "github.com/Fantom-foundation/go-opera/inter/validatorpk"
7 | "github.com/Fantom-foundation/go-opera/valkeystore/encryption"
8 | )
9 |
10 | type SyncedKeystore struct {
11 | backend KeystoreI
12 | mu sync.Mutex
13 | }
14 |
15 | func NewSyncedKeystore(backend KeystoreI) *SyncedKeystore {
16 | return &SyncedKeystore{
17 | backend: backend,
18 | }
19 | }
20 |
21 | func (s *SyncedKeystore) Unlocked(pubkey validatorpk.PubKey) bool {
22 | s.mu.Lock()
23 | defer s.mu.Unlock()
24 | return s.backend.Unlocked(pubkey)
25 | }
26 |
27 | func (s *SyncedKeystore) Has(pubkey validatorpk.PubKey) bool {
28 | s.mu.Lock()
29 | defer s.mu.Unlock()
30 | return s.backend.Has(pubkey)
31 | }
32 |
33 | func (s *SyncedKeystore) Unlock(pubkey validatorpk.PubKey, auth string) error {
34 | s.mu.Lock()
35 | defer s.mu.Unlock()
36 | return s.backend.Unlock(pubkey, auth)
37 | }
38 |
39 | func (s *SyncedKeystore) GetUnlocked(pubkey validatorpk.PubKey) (*encryption.PrivateKey, error) {
40 | s.mu.Lock()
41 | defer s.mu.Unlock()
42 | return s.backend.GetUnlocked(pubkey)
43 | }
44 |
45 | func (s *SyncedKeystore) Add(pubkey validatorpk.PubKey, key []byte, auth string) error {
46 | s.mu.Lock()
47 | defer s.mu.Unlock()
48 | return s.backend.Add(pubkey, key, auth)
49 | }
50 |
51 | func (s *SyncedKeystore) Get(pubkey validatorpk.PubKey, auth string) (*encryption.PrivateKey, error) {
52 | s.mu.Lock()
53 | defer s.mu.Unlock()
54 | return s.backend.Get(pubkey, auth)
55 | }
56 |
--------------------------------------------------------------------------------
/vecmt/no_cheaters.go:
--------------------------------------------------------------------------------
1 | package vecmt
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/hash"
7 | )
8 |
9 | // NoCheaters excludes events which are observed by selfParents as cheaters.
10 | // Called by emitter to exclude cheater's events from potential parents list.
11 | func (vi *Index) NoCheaters(selfParent *hash.Event, options hash.Events) hash.Events {
12 | if selfParent == nil {
13 | return options
14 | }
15 | vi.InitBranchesInfo()
16 |
17 | if !vi.Engine.AtLeastOneFork() {
18 | return options
19 | }
20 |
21 | // no need to merge, because every branch is marked by IsForkDetected if fork is observed
22 | highest := vi.Base.GetHighestBefore(*selfParent)
23 | filtered := make(hash.Events, 0, len(options))
24 | for _, id := range options {
25 | e := vi.getEvent(id)
26 | if e == nil {
27 | vi.crit(errors.New("event not found"))
28 | }
29 | if !highest.Get(vi.validatorIdxs[e.Creator()]).IsForkDetected() {
30 | filtered.Add(id)
31 | }
32 | }
33 | return filtered
34 | }
35 |
--------------------------------------------------------------------------------
/vecmt/store_vectors.go:
--------------------------------------------------------------------------------
1 | package vecmt
2 |
3 | import (
4 | "github.com/Fantom-foundation/lachesis-base/hash"
5 | "github.com/Fantom-foundation/lachesis-base/kvdb"
6 | )
7 |
8 | func (vi *Index) getBytes(table kvdb.Store, id hash.Event) []byte {
9 | key := id.Bytes()
10 | b, err := table.Get(key)
11 | if err != nil {
12 | vi.crit(err)
13 | }
14 | return b
15 | }
16 |
17 | func (vi *Index) setBytes(table kvdb.Store, id hash.Event, b []byte) {
18 | key := id.Bytes()
19 | err := table.Put(key, b)
20 | if err != nil {
21 | vi.crit(err)
22 | }
23 | }
24 |
25 | // GetHighestBeforeTime reads the vector from DB
26 | func (vi *Index) GetHighestBeforeTime(id hash.Event) *HighestBeforeTime {
27 | if bVal, okGet := vi.cache.HighestBeforeTime.Get(id); okGet {
28 | return bVal.(*HighestBeforeTime)
29 | }
30 |
31 | b := HighestBeforeTime(vi.getBytes(vi.table.HighestBeforeTime, id))
32 | if b == nil {
33 | return nil
34 | }
35 | vi.cache.HighestBeforeTime.Add(id, &b, uint(len(b)))
36 | return &b
37 | }
38 |
39 | // GetHighestBefore reads the vector from DB
40 | func (vi *Index) GetHighestBefore(id hash.Event) *HighestBefore {
41 | return &HighestBefore{
42 | VSeq: vi.Base.GetHighestBefore(id),
43 | VTime: vi.GetHighestBeforeTime(id),
44 | }
45 | }
46 |
47 | // SetHighestBeforeTime stores the vector into DB
48 | func (vi *Index) SetHighestBeforeTime(id hash.Event, vec *HighestBeforeTime) {
49 | vi.setBytes(vi.table.HighestBeforeTime, id, *vec)
50 |
51 | vi.cache.HighestBeforeTime.Add(id, vec, uint(len(*vec)))
52 | }
53 |
54 | // SetHighestBefore stores the vectors into DB
55 | func (vi *Index) SetHighestBefore(id hash.Event, vec *HighestBefore) {
56 | vi.Base.SetHighestBefore(id, vec.VSeq)
57 | vi.SetHighestBeforeTime(id, vec.VTime)
58 | }
59 |
--------------------------------------------------------------------------------
/vecmt/vector.go:
--------------------------------------------------------------------------------
1 | package vecmt
2 |
3 | import (
4 | "encoding/binary"
5 |
6 | "github.com/Fantom-foundation/lachesis-base/inter/idx"
7 | "github.com/Fantom-foundation/lachesis-base/vecfc"
8 |
9 | "github.com/Fantom-foundation/go-opera/inter"
10 | )
11 |
12 | /*
13 | * Use binary form for optimization, to avoid serialization. As a result, DB cache works as elements cache.
14 | */
15 |
16 | type (
17 | // HighestBeforeTime is a vector of highest events (their CreationTime) which are observed by source event
18 | HighestBeforeTime []byte
19 |
20 | HighestBefore struct {
21 | VSeq *vecfc.HighestBeforeSeq
22 | VTime *HighestBeforeTime
23 | }
24 | )
25 |
26 | // NewHighestBefore creates new HighestBefore vector.
27 | func NewHighestBefore(size idx.Validator) *HighestBefore {
28 | return &HighestBefore{
29 | VSeq: vecfc.NewHighestBeforeSeq(size),
30 | VTime: NewHighestBeforeTime(size),
31 | }
32 | }
33 |
34 | // NewHighestBeforeTime creates new HighestBeforeTime vector.
35 | func NewHighestBeforeTime(size idx.Validator) *HighestBeforeTime {
36 | b := make(HighestBeforeTime, size*8)
37 | return &b
38 | }
39 |
40 | // Get i's position in the byte-encoded vector clock
41 | func (b HighestBeforeTime) Get(i idx.Validator) inter.Timestamp {
42 | for i >= b.Size() {
43 | return 0
44 | }
45 | return inter.Timestamp(binary.LittleEndian.Uint64(b[i*8 : (i+1)*8]))
46 | }
47 |
48 | // Set i's position in the byte-encoded vector clock
49 | func (b *HighestBeforeTime) Set(i idx.Validator, time inter.Timestamp) {
50 | for i >= b.Size() {
51 | // append zeros if exceeds size
52 | *b = append(*b, []byte{0, 0, 0, 0, 0, 0, 0, 0}...)
53 | }
54 | binary.LittleEndian.PutUint64((*b)[i*8:(i+1)*8], uint64(time))
55 | }
56 |
57 | // Size of the vector clock
58 | func (b HighestBeforeTime) Size() idx.Validator {
59 | return idx.Validator(len(b) / 8)
60 | }
61 |
--------------------------------------------------------------------------------