├── .circleci └── config.yml ├── .codecov.yml ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── new_story.md └── pull_request_template.md ├── .gitignore ├── .gitmodules ├── .golangci.yml ├── CHANGELOG.md ├── CODEWALK.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── COPYRIGHT ├── Dockerfile ├── Dockerfile.ci.base ├── Dockerfile.ci.faucet ├── Dockerfile.ci.filecoin ├── Dockerfile.ci.genesis ├── Dockerfile.faucet ├── Dockerfile.genesis ├── KNOWN_ISSUES.md ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile ├── README.md ├── _assets └── arch-diagram.monopic ├── abi ├── abi.go ├── encode.go ├── encoding_test.go └── testing.go ├── actor ├── actor.go ├── actor_test.go ├── builtin │ ├── account │ │ ├── account.go │ │ └── account_test.go │ ├── builtin.go │ ├── initactor │ │ ├── init.go │ │ └── init_test.go │ ├── miner │ │ ├── miner.go │ │ ├── miner_internal_test.go │ │ ├── miner_test.go │ │ ├── sector_set.go │ │ └── sector_set_test.go │ ├── miner_redeem_test.go │ ├── paymentbroker │ │ ├── paymentbroker.go │ │ └── paymentbroker_test.go │ ├── storagemarket │ │ ├── storagemarket.go │ │ └── storagemarket_test.go │ └── testing.go ├── export.go ├── storage.go ├── storage_test.go └── testing.go ├── address ├── address.go ├── address_test.go ├── constants.go └── testing.go ├── appveyor.yml ├── bin ├── container_daemon ├── devnet_start └── node_restart ├── build ├── README.md ├── main.go └── tools │ ├── README.md │ └── tools.go ├── cborutil ├── msgreader.go ├── msgwriter.go └── rw_test.go ├── chain ├── bad_tipset_cache.go ├── get_ancestors.go ├── get_ancestors_test.go ├── init.go ├── message_store.go ├── message_store_test.go ├── reorg.go ├── reorg_test.go ├── status.go ├── status_test.go ├── store.go ├── store_test.go ├── syncer.go ├── syncer_integration_test.go ├── syncer_test.go ├── testing.go ├── tip_index.go ├── traversal.go ├── traversal_test.go └── util.go ├── clock ├── clock.go ├── ticker.go └── timer.go ├── commands ├── actor.go ├── actor_daemon_test.go ├── address.go ├── address_daemon_test.go ├── bitswap.go ├── bitswap_stats_daemon_test.go ├── bootstrap.go ├── bootstrap_daemon_test.go ├── chain.go ├── chain_daemon_test.go ├── client.go ├── client_daemon_test.go ├── commands_test.go ├── config.go ├── config_daemon_test.go ├── daemon.go ├── daemon_daemon_test.go ├── dag.go ├── dag_daemon_test.go ├── deals.go ├── deals_daemon_test.go ├── dht.go ├── dht_daemon_test.go ├── env.go ├── errors.go ├── id.go ├── id_daemon_test.go ├── init.go ├── init_daemon_test.go ├── inspector.go ├── inspector_daemon_test.go ├── inspector_test.go ├── leb128.go ├── leb128_test.go ├── log.go ├── main.go ├── main_daemon_test.go ├── main_test.go ├── message.go ├── message_daemon_test.go ├── miner.go ├── miner_daemon_test.go ├── mining.go ├── mining_daemon_test.go ├── mpool.go ├── mpool_daemon_test.go ├── outbox.go ├── outbox_daemon_test.go ├── payment_channel.go ├── payment_channel_daemon_test.go ├── ping.go ├── ping_daemon_test.go ├── protocol.go ├── protocol_cmd_test.go ├── retrieval_client.go ├── retrieval_client_daemon_test.go ├── show.go ├── show_test.go ├── stats.go ├── stats_daemon_test.go ├── swarm.go ├── swarm_daemon_test.go ├── util_test.go ├── utils.go ├── version.go └── version_daemon_test.go ├── config ├── config.go └── config_test.go ├── consensus ├── actor_state.go ├── actor_state_test.go ├── block_validation.go ├── block_validation_test.go ├── chain_selector.go ├── election.go ├── election_test.go ├── expected.go ├── expected_test.go ├── genesis.go ├── power_table_view.go ├── power_table_view_test.go ├── processor.go ├── processor_test.go ├── protocol.go ├── testing.go ├── validation.go ├── validation_test.go └── weight_test.go ├── crypto ├── crypto.go └── crypto_test.go ├── designdocs.md ├── exec └── exec.go ├── fixtures ├── constants.go ├── live │ └── .gitkeep ├── setup.json └── test │ └── .gitkeep ├── flags └── flags.go ├── functional-tests ├── faucet_test.go ├── lib │ └── helpers.bash ├── network-deployment │ ├── README.md │ ├── bootstrap_test.go │ ├── logging_test.go │ ├── miner_workflow_test.go │ └── relay_check_test.go ├── retrieval └── run ├── gengen ├── README.md ├── main.go └── util │ ├── gengen.go │ └── gengen_test.go ├── go.mod ├── go.sum ├── issue_template.md ├── main.go ├── message ├── handler.go ├── handler_integration_test.go ├── inbox.go ├── inbox_test.go ├── outbox.go ├── outbox_test.go ├── policy.go ├── policy_test.go ├── pool.go ├── pool_test.go ├── publisher.go ├── publisher_test.go ├── queue.go ├── queue_test.go ├── testing.go └── util.go ├── metrics ├── counter.go ├── export.go ├── gauge.go ├── heartbeat.go ├── heartbeat_test.go ├── log_json_formatter.go ├── timer.go ├── timer_test.go └── tracing │ └── util.go ├── mining ├── block_generate.go ├── mqueue.go ├── mqueue_test.go ├── scheduler.go ├── scheduler_test.go ├── testing.go ├── worker.go └── worker_test.go ├── net ├── address.go ├── address_test.go ├── bootstrap.go ├── bootstrap_test.go ├── graphsync_fetcher.go ├── graphsync_fetcher_test.go ├── network.go ├── peer_tracker.go ├── peer_tracker_test.go ├── pinger.go ├── protocols.go ├── pubsub │ ├── publisher.go │ ├── subscriber.go │ └── testing.go ├── router.go ├── topics.go ├── validators.go └── validators_test.go ├── networking.md ├── node ├── block.go ├── block_mining_submodule.go ├── block_propagate_test.go ├── blockservice_submoodule.go ├── blockstore_submodule.go ├── builder.go ├── chain_submodule.go ├── config.go ├── fault_slasher_submodule.go ├── hello_protocol_submodule.go ├── helpers.go ├── init.go ├── libp2p.go ├── message.go ├── message_propagate_test.go ├── messaging_submodule.go ├── network_submodule.go ├── node.go ├── node_test.go ├── retrieval_protocol_submodule.go ├── sector_builder_submodule.go ├── storage_networking_submodule.go ├── storage_protocol_submodule.go ├── test │ ├── api.go │ └── builder.go ├── testing.go └── wallet_submodule.go ├── paths └── paths.go ├── plumbing ├── api.go ├── cfg │ ├── config.go │ └── config_test.go ├── cst │ ├── chain_state.go │ └── chain_sync.go ├── dag │ ├── dag.go │ └── dag_test.go ├── msg │ ├── previewer.go │ ├── previewer_test.go │ ├── testing.go │ ├── waiter.go │ └── waiter_test.go └── strgdls │ ├── store.go │ └── store_test.go ├── porcelain ├── api.go ├── chain.go ├── client.go ├── client_test.go ├── miner.go ├── miner_test.go ├── mpool.go ├── mpool_test.go ├── network.go ├── network_test.go ├── payment_channel.go ├── payment_channel_test.go ├── payments.go ├── payments_test.go ├── protocol.go ├── protocol_test.go ├── sectorbuilder.go ├── sectorbuilder_test.go ├── storagedeals.go ├── storagedeals_test.go ├── wallet.go └── wallet_test.go ├── proofs ├── piece_commitment.go ├── sectorbuilder │ ├── bytesink │ │ ├── fifo.go │ │ └── interface.go │ ├── errors.go │ ├── interface.go │ ├── poller.go │ ├── rustsectorbuilder.go │ ├── testing │ │ ├── builder.go │ │ ├── harness.go │ │ └── interface_test.go │ ├── utils.go │ └── utils_test.go └── verification │ ├── interface.go │ ├── rustverifier.go │ └── testing.go ├── protocol ├── block │ ├── mining_api.go │ └── mining_api_test.go ├── hello │ ├── hello.go │ └── hello_test.go ├── retrieval │ ├── api.go │ ├── client.go │ ├── doc.go │ ├── miner.go │ ├── retrieval_protocol_test.go │ └── types.go └── storage │ ├── api.go │ ├── client.go │ ├── client_test.go │ ├── deals_awaiting_seal.go │ ├── deals_awaiting_seal_test.go │ ├── fault_slasher.go │ ├── fault_slasher_test.go │ ├── miner.go │ ├── miner_test.go │ ├── prover.go │ ├── prover_test.go │ ├── storage_protocol_test.go │ ├── storagedeal │ ├── state.go │ └── types.go │ └── testing.go ├── repo ├── fsrepo.go ├── fsrepo_test.go ├── mem.go ├── repo.go └── testing.go ├── rleplus ├── internal │ ├── bitvector.go │ └── bitvector_test.go ├── rleplus.go └── rleplus_test.go ├── sampling ├── chain_randomness.go └── chain_randomness_test.go ├── scripts ├── build-bundle.sh ├── install-filecoin-parameters.sh ├── install-go-bls-sigs.sh ├── install-go-sectorbuilder.sh ├── install-shared.bash ├── publish-release.sh └── update-badge.sh ├── state ├── cached_tree.go ├── cached_tree_test.go ├── testing.go ├── tree.go └── tree_test.go ├── testhelpers ├── chain.go ├── clock.go ├── clock_test.go ├── consensus.go ├── core.go ├── iptbtester │ ├── genesis.go │ └── wrapper.go ├── mining.go ├── net.go ├── output.go ├── test_daemon.go ├── testflags │ └── flags.go └── util.go ├── tools ├── fast │ ├── action_actor.go │ ├── action_address.go │ ├── action_bootstrap.go │ ├── action_chain.go │ ├── action_client.go │ ├── action_config.go │ ├── action_dag.go │ ├── action_deals.go │ ├── action_dht.go │ ├── action_id.go │ ├── action_inspector.go │ ├── action_message.go │ ├── action_miner.go │ ├── action_miner_test.go │ ├── action_mining.go │ ├── action_mpool.go │ ├── action_paych.go │ ├── action_ping.go │ ├── action_protocol.go │ ├── action_retrieval_client.go │ ├── action_show.go │ ├── action_swarm.go │ ├── action_wallet.go │ ├── bin │ │ └── localnet │ │ │ ├── README.md │ │ │ └── main.go │ ├── docs │ │ └── SHELL.md │ ├── environment │ │ ├── environment.go │ │ ├── environment_devnet.go │ │ ├── environment_memory_genesis.go │ │ └── environment_memory_genesis_test.go │ ├── fastesting │ │ ├── assertions.go │ │ ├── basic.go │ │ ├── basic_test.go │ │ ├── deployment.go │ │ ├── log_writer.go │ │ └── log_writer_test.go │ ├── fastutil │ │ ├── debug_utils.go │ │ ├── helpers_test.go │ │ ├── line_puller.go │ │ ├── line_puller_test.go │ │ ├── stream_recorder.go │ │ └── stream_recorder_test.go │ ├── process.go │ ├── process_action_options.go │ ├── process_options.go │ ├── process_stderr_recorder.go │ ├── process_stderr_recorder_test.go │ ├── process_test.go │ ├── series │ │ ├── connect.go │ │ ├── create_miner_with_ask.go │ │ ├── ctx_mining_once.go │ │ ├── ctx_sleep_delay.go │ │ ├── find_deal_by_id.go │ │ ├── get_head_block_height.go │ │ ├── import_and_store.go │ │ ├── init_and_start.go │ │ ├── send_filecoin_defaults.go │ │ ├── send_filecoin_from_default.go │ │ ├── set_price_ask.go │ │ ├── setup_genesis_node.go │ │ ├── wait_for_block_height.go │ │ ├── wait_for_chain_message.go │ │ ├── wait_for_deal_state.go │ │ └── with_wallet.go │ └── tests │ │ └── retrieval_test.go ├── faucet │ ├── limiter │ │ ├── limiter.go │ │ └── limiter_test.go │ └── main.go ├── genesis-file-server │ └── main.go ├── iptb-plugins │ ├── Makefile │ ├── README.md │ └── filecoin │ │ ├── Makefile │ │ ├── docker │ │ ├── dockerfilecoin.go │ │ ├── dockerfilecoin │ │ │ └── plugin.go │ │ ├── iptb_metrics.go │ │ ├── scripts │ │ │ └── prepMining.sh │ │ └── util.go │ │ ├── local │ │ ├── copy_file.go │ │ ├── copy_file_linux.go │ │ ├── filecoinutil.go │ │ ├── iptb_metrics.go │ │ ├── localfilecoin.go │ │ ├── localfilecoin │ │ │ └── plugin.go │ │ └── scripts │ │ │ └── prepMining.sh │ │ ├── mock │ │ ├── mockfilecoin.go │ │ └── mockfilecoin_metrics.go │ │ └── util.go ├── migration │ ├── README.md │ ├── internal │ │ ├── default_migrations_provider.go │ │ ├── logger.go │ │ ├── logger_test.go │ │ ├── repo_fs_helpers.go │ │ ├── repo_fs_helpers_test.go │ │ ├── runner.go │ │ ├── runner_buildonly_test.go │ │ ├── runner_install_test.go │ │ ├── runner_migrate_test.go │ │ ├── runner_test.go │ │ └── test_helpers.go │ ├── main.go │ ├── main_test.go │ ├── main_whitebox_test.go │ └── migrations │ │ └── repo-1-2 │ │ ├── fixtures │ │ └── repo-1.tgz │ │ └── migration.go └── prerelease-tool │ ├── main.go │ └── main_test.go ├── types ├── atto_fil.go ├── atto_fil_test.go ├── block.go ├── block_height.go ├── block_height_test.go ├── block_test.go ├── bytes_amount.go ├── bytes_amount_test.go ├── bytes_test.go ├── chain_info.go ├── channel_id.go ├── channel_id_test.go ├── commitments.go ├── constants.go ├── fault_set.go ├── fault_set_test.go ├── fixed_point.go ├── fixed_point_test.go ├── full_block.go ├── helpers.go ├── intset.go ├── intset_test.go ├── keyinfo.go ├── keyinfo_test.go ├── message.go ├── message_receipt.go ├── message_receipt_test.go ├── message_test.go ├── metered_message.go ├── metered_message_test.go ├── payment_voucher.go ├── payment_voucher_test.go ├── porep_proof_partitions.go ├── post_proof_partitions.go ├── proofs.go ├── proofs_mode.go ├── recoverer.go ├── sector_class.go ├── sector_size.go ├── signature.go ├── signed_message.go ├── signed_message_test.go ├── signer.go ├── testing.go ├── testing_messages.go ├── testing_test.go ├── ticket.go ├── tipset.go ├── tipset_key.go ├── tipset_key_test.go ├── tipset_test.go ├── uint64.go └── uint64_test.go ├── util ├── convert │ └── convert.go ├── moresync │ ├── latch.go │ └── latch_test.go └── version │ ├── version.go │ └── version_test.go ├── version ├── protocol_version_table.go ├── protocol_version_table_test.go └── protocol_versions.go ├── vm ├── context.go ├── context_test.go ├── errors │ ├── errors.go │ ├── errors_test.go │ └── vm_errors.go ├── gas_tracker.go ├── storage.go ├── storage_test.go ├── vm.go └── vm_test.go └── wallet ├── backend.go ├── dsbackend.go ├── dsbackend_test.go ├── signature_test.go ├── util └── util.go ├── wallet.go └── wallet_test.go /.codecov.yml: -------------------------------------------------------------------------------- 1 | # "documentation": https://gist.github.com/stevepeak/53bee7b2c326b24a9b4a 2 | coverage: 3 | range: 50..100 4 | round: down 5 | precision: 0 6 | 7 | status: 8 | project: false 9 | patch: false 10 | changes: false 11 | 12 | # https://docs.codecov.io/docs/pull-request-comments 13 | comment: 14 | layout: "diff" # "diff, flags, files" 15 | behavior: default 16 | require_changes: false # if true: only post the comment if coverage changes 17 | require_base: true # [yes :: must have a base report to post] 18 | require_head: true # [yes :: must have a head report to post] 19 | branches: [] # branch names that can post comment 20 | 21 | ignore: 22 | - "*/testing.go" 23 | 24 | codecov: 25 | notify: 26 | # yes: will delay sending notifications until all ci is finished 27 | # no: will send notifications without checking ci status and wait till "after_n_builds" are uploaded 28 | require_ci_to_pass: false 29 | # number of expected builds to receive before sending notifications 30 | # we can set this to prevent notifications of partial results due to CI parallelism 31 | # set this with respect to the sum of test parallelism in Circle CI configuration. 32 | after_n_builds: 6 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | labels: C-bug, candidate 5 | assignees: '' 6 | 7 | --- 8 | 12 | 13 | **Describe the bug**: 14 | 15 | **Expected behavior**: 16 | 17 | **Diagnostic information:** 18 | 19 | 20 | - Filecoin Version: 21 | - Filecoin Inspect Output: 22 | - Initialization Command: 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new_story.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New story 3 | about: Create a new story. Typically created after design intent is written down and 4 | subjected to constructive feedback (see CONTRIBUTING.md). 5 | title: '' 6 | labels: candidate 7 | assignees: '' 8 | 9 | --- 10 | ### Description 11 | Please first see README for how to get help before filing a new issue. 12 | 13 | ### Acceptance criteria 14 | 15 | ### Risks + pitfalls 16 | 17 | ### Where to begin 18 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Motivation 2 | 3 | 4 | ### Proposed changes 5 | 6 | Closes issue # 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | go-filecoin 2 | .task 3 | *.coverprofile 4 | *.out 5 | *.so 6 | .idea 7 | gengen/gengen 8 | gengen/gensetup 9 | fixtures/test 10 | !fixtures/test/.gitkeep 11 | fixtures/live 12 | !fixtures/live/.gitkeep 13 | tools/fast/bin/localnet 14 | tools/faucet/faucet 15 | tools/aggregator/aggregator 16 | tools/genesis-file-server/genesis-file-server 17 | tools/migration/go-filecoin-migrate 18 | tools/prerelease-tool/prerelease-tool 19 | **/paramcache 20 | **/*.h 21 | **/*.a 22 | **/*.pc 23 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "go-bls-sigs"] 2 | path = go-bls-sigs 3 | url = https://github.com/filecoin-project/go-bls-sigs.git 4 | [submodule "go-sectorbuilder"] 5 | path = go-sectorbuilder 6 | url = https://github.com/filecoin-project/go-sectorbuilder.git 7 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | disable-all: true 3 | enable: 4 | - vet 5 | - gofmt 6 | - misspell 7 | - goconst 8 | - golint 9 | - errcheck 10 | - unconvert 11 | - staticcheck 12 | - varcheck 13 | - structcheck 14 | - deadcode 15 | 16 | issues: 17 | exclude-use-default: false 18 | 19 | linters-settings: 20 | goconst: 21 | min-occurrences: 6 22 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | This library is dual-licensed under Apache 2.0 and MIT terms. 2 | -------------------------------------------------------------------------------- /Dockerfile.ci.base: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-20190204-slim AS base 2 | MAINTAINER Filecoin Dev Team 3 | 4 | RUN apt-get update && apt-get install -y ca-certificates file sudo git build-essential wget 5 | 6 | # This docker file is a modified version of 7 | # https://github.com/ipfs/go-ipfs/blob/master/Dockerfile 8 | # Thanks Lars :) 9 | 10 | # Get su-exec, a very minimal tool for dropping privileges, 11 | # and tini, a very minimal init daemon for containers 12 | ENV SUEXEC_VERSION v0.2 13 | ENV TINI_VERSION v0.16.1 14 | RUN set -x \ 15 | && cd /tmp \ 16 | && git clone https://github.com/ncopa/su-exec.git \ 17 | && cd su-exec \ 18 | && git checkout -q $SUEXEC_VERSION \ 19 | && make \ 20 | && cd /tmp \ 21 | && wget -q -O tini https://github.com/krallin/tini/releases/download/$TINI_VERSION/tini \ 22 | && chmod +x tini 23 | -------------------------------------------------------------------------------- /Dockerfile.ci.faucet: -------------------------------------------------------------------------------- 1 | FROM busybox:1.30.1-glibc 2 | MAINTAINER Filecoin Dev Team 3 | 4 | # Get the binary, entrypoint script, and TLS CAs from the build container. 5 | COPY tools/faucet/faucet /usr/local/bin/faucet 6 | COPY --from=filecoin:all /tmp/su-exec/su-exec /sbin/su-exec 7 | COPY --from=filecoin:all /tmp/tini /sbin/tini 8 | COPY --from=filecoin:all /etc/ssl/certs /etc/ssl/certs 9 | COPY --from=filecoin:all /lib/x86_64-linux-gnu/libutil.so.1 /lib/libutil.so.1 10 | COPY --from=filecoin:all /lib/x86_64-linux-gnu/libdl-2.24.so /lib/libdl.so.2 11 | COPY --from=filecoin:all /lib/x86_64-linux-gnu/librt.so.1 /lib/librt.so.1 12 | COPY --from=filecoin:all /lib/x86_64-linux-gnu/libgcc_s.so.1 /lib/libgcc_s.so.1 13 | 14 | RUN chmod +x /usr/local/bin/faucet 15 | 16 | EXPOSE 9797 17 | 18 | # There's an fs-repo, and initializes one if there isn't. 19 | ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/faucet"] 20 | -------------------------------------------------------------------------------- /Dockerfile.ci.genesis: -------------------------------------------------------------------------------- 1 | FROM busybox:1.30.1-glibc 2 | MAINTAINER Filecoin Dev Team 3 | 4 | # Get the binary, entrypoint script, and TLS CAs from the build container. 5 | COPY tools/genesis-file-server/genesis-file-server /usr/local/bin/genesis-file-server 6 | COPY fixtures/* /data/ 7 | COPY --from=filecoin:all /tmp/su-exec/su-exec /sbin/su-exec 8 | COPY --from=filecoin:all /tmp/tini /sbin/tini 9 | COPY --from=filecoin:all /etc/ssl/certs /etc/ssl/certs 10 | 11 | RUN chmod +x /usr/local/bin/genesis-file-server 12 | 13 | EXPOSE 8080 14 | 15 | # There's an fs-repo, and initializes one if there isn't. 16 | ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/genesis-file-server", "-port=8080", "-genesis-file-path=/opt/genesis/genesis.car"] 17 | -------------------------------------------------------------------------------- /Dockerfile.genesis: -------------------------------------------------------------------------------- 1 | FROM golang:1.12.1-stretch 2 | MAINTAINER Filecoin Dev Team 3 | 4 | RUN apt-get update && apt-get install -y ca-certificates file sudo clang 5 | RUN curl -sSf https://sh.rustup.rs | sh -s -- -y 6 | 7 | # This docker file is a modified version of 8 | # https://github.com/ipfs/go-ipfs/blob/master/Dockerfile 9 | # Thanks Lars :) 10 | 11 | ENV SRC_DIR /go/src/github.com/filecoin-project/go-filecoin 12 | ENV GO111MODULE on 13 | 14 | COPY . $SRC_DIR 15 | 16 | # Build genesis server 17 | RUN cd $SRC_DIR \ 18 | && . $HOME/.cargo/env \ 19 | && go build -o ./genesis-file-server ./tools/genesis-file-server/main.go 20 | 21 | RUN cd 22 | 23 | # Get su-exec, a very minimal tool for dropping privileges, 24 | # and tini, a very minimal init daemon for containers 25 | ENV SUEXEC_VERSION v0.2 26 | ENV TINI_VERSION v0.16.1 27 | RUN set -x \ 28 | && cd /tmp \ 29 | && git clone https://github.com/ncopa/su-exec.git \ 30 | && cd su-exec \ 31 | && git checkout -q $SUEXEC_VERSION \ 32 | && make \ 33 | && cd /tmp \ 34 | && wget -q -O tini https://github.com/krallin/tini/releases/download/$TINI_VERSION/tini \ 35 | && chmod +x tini 36 | 37 | 38 | # Now comes the actual target image, which aims to be as small as possible. 39 | FROM busybox:1.30.1-glibc 40 | MAINTAINER Filecoin Dev Team 41 | 42 | # Get the binary, entrypoint script, and TLS CAs from the build container. 43 | ENV SRC_DIR /go/src/github.com/filecoin-project/go-filecoin 44 | COPY --from=0 $SRC_DIR/genesis-file-server /usr/local/bin/genesis-file-server 45 | COPY --from=0 /tmp/su-exec/su-exec /sbin/su-exec 46 | COPY --from=0 /tmp/tini /sbin/tini 47 | COPY --from=0 /etc/ssl/certs /etc/ssl/certs 48 | 49 | EXPOSE 8080 50 | 51 | # There's an fs-repo, and initializes one if there isn't. 52 | ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/genesis-file-server", "-port=8080", "-genesis-file-path=/opt/genesis/genesis.car"] 53 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Filecoin Project 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 4 | 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 8 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Filecoin Project 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | go run ./build/*.go build 3 | 4 | deps: 5 | go run ./build/*.go smartdeps 6 | 7 | # WARNING THIS BUILDS A GO PLUGIN AND PLUGINS *DO NOT* WORK ON WINDOWS SYSTEMS 8 | iptb: 9 | make -C tools/iptb-plugins all 10 | -------------------------------------------------------------------------------- /_assets/arch-diagram.monopic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirmaChain/go-filecoin/4fcb713a209be0efac91da709cabbcfe89ceee7c/_assets/arch-diagram.monopic -------------------------------------------------------------------------------- /abi/testing.go: -------------------------------------------------------------------------------- 1 | package abi 2 | 3 | // MustConvertParams abi encodes the given parameters into a byte array (or panics) 4 | func MustConvertParams(params ...interface{}) []byte { 5 | vals, err := ToValues(params) 6 | if err != nil { 7 | panic(err) 8 | } 9 | 10 | out, err := EncodeValues(vals) 11 | if err != nil { 12 | panic(err) 13 | } 14 | return out 15 | } 16 | -------------------------------------------------------------------------------- /actor/builtin/account/account_test.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "testing" 5 | 6 | cbor "github.com/ipfs/go-ipld-cbor" 7 | 8 | "github.com/stretchr/testify/require" 9 | 10 | "github.com/filecoin-project/go-filecoin/actor" 11 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 12 | "github.com/filecoin-project/go-filecoin/types" 13 | ) 14 | 15 | func TestAccountActorCborMarshaling(t *testing.T) { 16 | tf.UnitTest(t) 17 | 18 | t.Run("CBOR decode(encode(Actor)) == identity(Actor)", func(t *testing.T) { 19 | preEncode, _ := NewActor(types.NewAttoFILFromFIL(100)) 20 | out, err := cbor.DumpObject(preEncode) 21 | require.NoError(t, err) 22 | 23 | var postDecode actor.Actor 24 | err = cbor.DecodeInto(out, &postDecode) 25 | require.NoError(t, err) 26 | 27 | c1, _ := preEncode.Cid() 28 | require.NoError(t, err) 29 | 30 | c2, _ := postDecode.Cid() 31 | require.NoError(t, err) 32 | 33 | types.AssertCidsEqual(t, c1, c2) 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /actor/builtin/initactor/init_test.go: -------------------------------------------------------------------------------- 1 | package initactor_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/filecoin-project/go-filecoin/actor" 7 | . "github.com/filecoin-project/go-filecoin/actor/builtin/initactor" 8 | "github.com/filecoin-project/go-filecoin/address" 9 | th "github.com/filecoin-project/go-filecoin/testhelpers" 10 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 11 | "github.com/filecoin-project/go-filecoin/types" 12 | "github.com/ipfs/go-ipld-cbor" 13 | "github.com/magiconair/properties/assert" 14 | "github.com/stretchr/testify/require" 15 | ) 16 | 17 | func TestInitActorCreateInitActor(t *testing.T) { 18 | tf.UnitTest(t) 19 | 20 | initExecActor := &Actor{} 21 | 22 | storageMap := th.VMStorage() 23 | initActor := &actor.Actor{} 24 | storage := storageMap.NewStorage(address.InitAddress, initActor) 25 | 26 | // create state with a network name 27 | initExecActor.InitializeState(storage, "foo") 28 | storage.Flush() 29 | 30 | // retrieve state directly and assert it's constructed correctly 31 | state, err := storage.Get(initActor.Head) 32 | require.NoError(t, err) 33 | 34 | var initState State 35 | err = cbornode.DecodeInto(state, &initState) 36 | require.NoError(t, err) 37 | 38 | assert.Equal(t, "foo", initState.Network) 39 | } 40 | 41 | func TestInitActorGetNetwork(t *testing.T) { 42 | tf.UnitTest(t) 43 | 44 | initExecActor := &Actor{} 45 | state := &State{ 46 | Network: "bar", 47 | } 48 | 49 | msg := types.NewMessage(address.TestAddress, address.InitAddress, 0, types.ZeroAttoFIL, "getAddress", []byte{}) 50 | vmctx := th.NewFakeVMContext(msg, state) 51 | 52 | network, code, err := initExecActor.GetNetwork(vmctx) 53 | require.NoError(t, err) 54 | require.Equal(t, uint8(0), code) 55 | 56 | assert.Equal(t, "bar", network) 57 | } 58 | -------------------------------------------------------------------------------- /actor/builtin/testing.go: -------------------------------------------------------------------------------- 1 | package builtin 2 | 3 | import ( 4 | "testing" 5 | 6 | cbor "github.com/ipfs/go-ipld-cbor" 7 | 8 | "github.com/filecoin-project/go-filecoin/actor" 9 | "github.com/filecoin-project/go-filecoin/address" 10 | "github.com/filecoin-project/go-filecoin/vm" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | // RequireReadState constructs vm storage from the storage map and reads the chunk at the given actor's head 15 | func RequireReadState(t *testing.T, vms vm.StorageMap, addr address.Address, act *actor.Actor, state interface{}) { 16 | chunk, err := vms.NewStorage(addr, act).Get(act.Head) // address arbitrary 17 | require.NoError(t, err) 18 | 19 | err = cbor.DecodeInto(chunk, state) 20 | require.NoError(t, err) 21 | } 22 | -------------------------------------------------------------------------------- /address/testing.go: -------------------------------------------------------------------------------- 1 | package address 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // NewForTestGetter returns a closure that returns an address unique to that invocation. 8 | // The address is unique wrt the closure returned, not globally. 9 | func NewForTestGetter() func() Address { 10 | i := 0 11 | return func() Address { 12 | s := fmt.Sprintf("address%d", i) 13 | i++ 14 | newAddr, err := NewActorAddress([]byte(s)) 15 | if err != nil { 16 | panic(err) 17 | } 18 | return newAddr 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{build}" 2 | 3 | # Source Config 4 | 5 | clone_folder: c:\gopath\src\github.com\filecoin-project\go-filecoin 6 | 7 | # Build host 8 | 9 | environment: 10 | GOPATH: c:\gopath 11 | GOVERSION: 1.9 12 | 13 | init: 14 | - git config --global core.autocrlf input 15 | 16 | # Build 17 | 18 | install: 19 | # Install the specific Go version. 20 | - rmdir c:\go /s /q 21 | - appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi 22 | - msiexec /i go%GOVERSION%.windows-amd64.msi /q 23 | - choco install bzr 24 | - set Path=c:\go\bin;c:\gopath\bin;C:\Program Files (x86)\Bazaar\;C:\Program Files\Mercurial\%Path% 25 | - go version 26 | - go env 27 | 28 | build: false 29 | deploy: false 30 | 31 | test_script: 32 | - go run build\main.go deps 33 | - go run build\main.go test 34 | -------------------------------------------------------------------------------- /bin/container_daemon: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | user=filecoin 4 | repo="$FILECOIN_PATH" 5 | 6 | if [ `id -u` -eq 0 ]; then 7 | echo "Changing user to $user" 8 | # ensure folder is writable 9 | su-exec "$user" test -w "$repo" || chown -R -- "$user" "$repo" 10 | # restart script with new privileges 11 | exec su-exec "$user" "$0" "$@" 12 | fi 13 | 14 | if [ -e "$repo/config.json" ]; then 15 | echo "Found Filecoin fs-repo at $repo" 16 | else 17 | go-filecoin init 18 | # TODO configure custom API and address here 19 | fi 20 | 21 | # if the first argument is daemon 22 | if [ "$1" = "daemon" ]; then 23 | shift 24 | else 25 | echo "ERROR: arguments have been set but the first argument isn't 'daemon'" >&2 26 | fi 27 | 28 | exec go-filecoin daemon "$@" 29 | -------------------------------------------------------------------------------- /bin/devnet_start: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "checking if node was restarted" 4 | jq -r -e '.mining .minerAddress | length > 0' /var/local/filecoin/repo/config.json > /dev/null 2>@1 5 | if [ "$?" -eq "0" ]; then 6 | echo "minerAddress exists, likely restart" 7 | (/usr/local/bin/node_restart)& 8 | fi 9 | 10 | exec /usr/local/bin/start_filecoin "$@" 11 | -------------------------------------------------------------------------------- /bin/node_restart: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | filecoin_repo="/var/local/filecoin/repo" 4 | filecoin_exec="go-filecoin --repodir=${filecoin_repo}" 5 | 6 | # Number of time to check before giving up 7 | limit=3600 8 | count=0 9 | while ! ${filecoin_exec} id >&2 2> /dev/null 10 | do 11 | echo "Waiting for daemon to start..." && sleep 1 12 | count=`expr $count + 1` 13 | if [ "$count" -gt "$limit" ]; then 14 | echo "API did not come online in $limit seconds" 15 | exit 1 16 | fi 17 | done 18 | 19 | for node_addr in $(cat /var/filecoin/car/peers.txt) 20 | do 21 | echo "re-joining with peer at: ${node_addr}" 22 | $filecoin_exec swarm connect "${node_addr}" || true 23 | done 24 | 25 | ${filecoin_exec} mining start 26 | -------------------------------------------------------------------------------- /build/README.md: -------------------------------------------------------------------------------- 1 | # Build Scripts 2 | 3 | This package contains cross platform scripts to make development easy on all operating systems. 4 | -------------------------------------------------------------------------------- /build/tools/README.md: -------------------------------------------------------------------------------- 1 | This package depends on build tools that should be fetched with `go mod`. It 2 | should not be built or linted. 3 | -------------------------------------------------------------------------------- /build/tools/tools.go: -------------------------------------------------------------------------------- 1 | // +build tools 2 | 3 | // Build tools for go mod 4 | package tools 5 | 6 | import ( 7 | _ "github.com/golangci/golangci-lint/cmd/golangci-lint" 8 | _ "github.com/jstemmer/go-junit-report" 9 | ) 10 | -------------------------------------------------------------------------------- /cborutil/msgreader.go: -------------------------------------------------------------------------------- 1 | package cborutil 2 | 3 | import ( 4 | "bufio" 5 | "encoding/binary" 6 | "fmt" 7 | "io" 8 | 9 | cbor "github.com/ipfs/go-ipld-cbor" 10 | ) 11 | 12 | // MaxMessageSize is the maximum message size to read 13 | const MaxMessageSize = 256 << 10 14 | 15 | // ErrMessageTooLarge is returned when reading too big of a message 16 | var ErrMessageTooLarge = fmt.Errorf("attempted to read a message larger than the limit") 17 | 18 | // MsgReader is a cbor message reader 19 | type MsgReader struct { 20 | br *bufio.Reader 21 | } 22 | 23 | // NewMsgReader returns a new MsgReader 24 | func NewMsgReader(r io.Reader) *MsgReader { 25 | return &MsgReader{ 26 | br: bufio.NewReader(r), 27 | } 28 | } 29 | 30 | // ReadMsg reads a length delimited cbor message into the given object 31 | func (mr *MsgReader) ReadMsg(i interface{}) error { 32 | l, err := binary.ReadUvarint(mr.br) 33 | if err != nil { 34 | return err 35 | } 36 | 37 | if l > MaxMessageSize { 38 | return ErrMessageTooLarge 39 | } 40 | 41 | // TODO: add a method in ipldcbor that accepts a reader so we can use the streaming unmarshalers 42 | // refmtcbor.NewUnmarshallerAtlased(mr.br, ipldcbor.Atlas) 43 | 44 | buf := make([]byte, l) 45 | _, err = io.ReadFull(mr.br, buf) 46 | if err != nil { 47 | return err 48 | } 49 | 50 | return cbor.DecodeInto(buf, i) 51 | } 52 | -------------------------------------------------------------------------------- /cborutil/msgwriter.go: -------------------------------------------------------------------------------- 1 | package cborutil 2 | 3 | import ( 4 | "bufio" 5 | "encoding/binary" 6 | "io" 7 | 8 | cbor "github.com/ipfs/go-ipld-cbor" 9 | ) 10 | 11 | // MsgWriter is a length delimited cbor message writer 12 | type MsgWriter struct { 13 | w *bufio.Writer 14 | } 15 | 16 | // NewMsgWriter returns a new MsgWriter 17 | func NewMsgWriter(w io.Writer) *MsgWriter { 18 | return &MsgWriter{ 19 | w: bufio.NewWriter(w), 20 | } 21 | } 22 | 23 | // WriteMsg writes the given object as a length delimited cbor blob 24 | func (mw *MsgWriter) WriteMsg(i interface{}) error { 25 | // TODO: rewrite to be more memory efficient once we hook up the streaming 26 | // cbor interfaces 27 | data, err := cbor.DumpObject(i) 28 | if err != nil { 29 | return err 30 | } 31 | 32 | buf := make([]byte, binary.MaxVarintLen64) 33 | n := binary.PutUvarint(buf, uint64(len(data))) 34 | _, err = mw.w.Write(buf[:n]) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | _, err = mw.w.Write(data) 40 | if err != nil { 41 | return err 42 | } 43 | 44 | return mw.w.Flush() 45 | } 46 | -------------------------------------------------------------------------------- /cborutil/rw_test.go: -------------------------------------------------------------------------------- 1 | package cborutil 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | cbor "github.com/ipfs/go-ipld-cbor" 8 | 9 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func init() { 14 | cbor.RegisterCborType(fooTestMessage{}) 15 | } 16 | 17 | type fooTestMessage struct { 18 | A string 19 | B int 20 | } 21 | 22 | func TestMessageSending(t *testing.T) { 23 | tf.UnitTest(t) 24 | 25 | buf := new(bytes.Buffer) 26 | w := NewMsgWriter(buf) 27 | r := NewMsgReader(buf) 28 | 29 | items := []fooTestMessage{ 30 | {A: "cat", B: 17}, 31 | {A: "dog", B: 93}, 32 | {A: "bear", B: 41}, 33 | {A: "fish", B: 101}, 34 | } 35 | 36 | for _, it := range items { 37 | assert.NoError(t, w.WriteMsg(it)) 38 | } 39 | 40 | for _, it := range items { 41 | var msg fooTestMessage 42 | assert.NoError(t, r.ReadMsg(&msg)) 43 | assert.Equal(t, it, msg) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /chain/bad_tipset_cache.go: -------------------------------------------------------------------------------- 1 | package chain 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/filecoin-project/go-filecoin/types" 7 | ) 8 | 9 | // badTipSetCache keeps track of bad tipsets that the syncer should not try to 10 | // download. Readers and writers grab a lock. The purpose of this cache is to 11 | // prevent a node from having to repeatedly invalidate a block (and its children) 12 | // in the event that the tipset does not conform to the rules of consensus. Note 13 | // that the cache is only in-memory, so it is reset whenever the node is restarted. 14 | // TODO: this needs to be limited. 15 | type badTipSetCache struct { 16 | mu sync.Mutex 17 | bad map[string]struct{} 18 | } 19 | 20 | // AddChain adds the chain of tipsets to the badTipSetCache. For now it just 21 | // does the simplest thing and adds all blocks of the chain to the cache. 22 | // TODO: might want to cache a random subset once cache size is limited. 23 | func (cache *badTipSetCache) AddChain(chain []types.TipSet) { 24 | for _, ts := range chain { 25 | cache.Add(ts.String()) 26 | } 27 | } 28 | 29 | // Add adds a single tipset key to the badTipSetCache. 30 | func (cache *badTipSetCache) Add(tsKey string) { 31 | cache.mu.Lock() 32 | defer cache.mu.Unlock() 33 | cache.bad[tsKey] = struct{}{} 34 | } 35 | 36 | // Has checks for membership in the badTipSetCache. 37 | func (cache *badTipSetCache) Has(tsKey string) bool { 38 | cache.mu.Lock() 39 | defer cache.mu.Unlock() 40 | _, ok := cache.bad[tsKey] 41 | return ok 42 | } 43 | -------------------------------------------------------------------------------- /chain/message_store_test.go: -------------------------------------------------------------------------------- 1 | package chain_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/ipfs/go-hamt-ipld" 8 | "github.com/stretchr/testify/assert" 9 | 10 | "github.com/filecoin-project/go-filecoin/chain" 11 | "github.com/filecoin-project/go-filecoin/types" 12 | ) 13 | 14 | func TestMessageStoreMessagesHappy(t *testing.T) { 15 | ctx := context.Background() 16 | keys := types.MustGenerateKeyInfo(2, 42) 17 | mm := types.NewMessageMaker(t, keys) 18 | 19 | alice := mm.Addresses()[0] 20 | bob := mm.Addresses()[1] 21 | 22 | msgs := []*types.SignedMessage{ 23 | mm.NewSignedMessage(alice, 0), 24 | mm.NewSignedMessage(alice, 1), 25 | mm.NewSignedMessage(bob, 0), 26 | mm.NewSignedMessage(alice, 2), 27 | mm.NewSignedMessage(alice, 3), 28 | mm.NewSignedMessage(bob, 1), 29 | mm.NewSignedMessage(alice, 4), 30 | mm.NewSignedMessage(bob, 2), 31 | } 32 | 33 | ms := chain.NewMessageStore(hamt.NewCborStore()) 34 | msgsCid, err := ms.StoreMessages(ctx, msgs) 35 | assert.NoError(t, err) 36 | 37 | rtMsgs, err := ms.LoadMessages(ctx, msgsCid) 38 | assert.NoError(t, err) 39 | 40 | assert.Equal(t, msgs, rtMsgs) 41 | } 42 | 43 | func TestMessageStoreReceiptsHappy(t *testing.T) { 44 | ctx := context.Background() 45 | mr := types.NewReceiptMaker() 46 | 47 | receipts := []*types.MessageReceipt{ 48 | mr.NewReceipt(), 49 | mr.NewReceipt(), 50 | mr.NewReceipt(), 51 | } 52 | 53 | ms := chain.NewMessageStore(hamt.NewCborStore()) 54 | receiptCids, err := ms.StoreReceipts(ctx, receipts) 55 | assert.NoError(t, err) 56 | 57 | rtReceipts, err := ms.LoadReceipts(ctx, receiptCids) 58 | assert.NoError(t, err) 59 | 60 | assert.Equal(t, receipts, rtReceipts) 61 | } 62 | -------------------------------------------------------------------------------- /chain/reorg.go: -------------------------------------------------------------------------------- 1 | package chain 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | 6 | "github.com/filecoin-project/go-filecoin/types" 7 | ) 8 | 9 | // IsReorg determines if choosing the end of the newChain as the new head 10 | // would cause a "reorg" given the current head is at curHead. 11 | // A reorg occurs when the old head is not a member of the new chain AND the 12 | // old head is not a subset of the new head. 13 | func IsReorg(old, new, commonAncestor types.TipSet) bool { 14 | oldSortedSet := old.Key() 15 | newSortedSet := new.Key() 16 | 17 | return !(&newSortedSet).ContainsAll(oldSortedSet) && !commonAncestor.Equals(old) 18 | } 19 | 20 | // ReorgDiff returns the dropped and added block heights resulting from the 21 | // reorg given the old and new heads and their common ancestor. 22 | func ReorgDiff(old, new, commonAncestor types.TipSet) (uint64, uint64, error) { 23 | hOld, err := old.Height() 24 | if err != nil { 25 | return 0, 0, err 26 | } 27 | 28 | hNew, err := new.Height() 29 | if err != nil { 30 | return 0, 0, err 31 | } 32 | 33 | hCommon, err := commonAncestor.Height() 34 | if err != nil { 35 | return 0, 0, err 36 | } 37 | 38 | if hCommon > hOld || hCommon > hNew { 39 | return 0, 0, errors.New("invalid common ancestor") 40 | } 41 | 42 | return hOld - hCommon, hNew - hCommon, nil 43 | } 44 | -------------------------------------------------------------------------------- /chain/status_test.go: -------------------------------------------------------------------------------- 1 | package chain 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | //"github.com/stretchr/testify/require" 8 | 9 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 10 | "github.com/filecoin-project/go-filecoin/types" 11 | ) 12 | 13 | func TestStatus(t *testing.T) { 14 | tf.UnitTest(t) 15 | 16 | sr := NewStatusReporter() 17 | assert.Equal(t, *newDefaultChainStatus(), sr.Status()) 18 | assert.Equal(t, newDefaultChainStatus().String(), sr.Status().String()) 19 | 20 | // single update 21 | cidFn := types.NewCidForTestGetter() 22 | t0 := types.NewTipSetKey(cidFn()) 23 | sr.UpdateStatus(validateHead(t0)) 24 | assert.Equal(t, t0, sr.Status().ValidatedHead) 25 | 26 | // multi update 27 | t1 := types.NewTipSetKey(cidFn()) 28 | t2 := types.NewTipSetKey(cidFn()) 29 | t3 := types.NewTipSetKey(cidFn()) 30 | expStatus := Status{ 31 | ValidatedHead: t1, 32 | ValidatedHeadHeight: 1, 33 | SyncingHead: t2, 34 | SyncingHeight: 456, 35 | SyncingTrusted: true, 36 | SyncingStarted: 123, 37 | SyncingComplete: false, 38 | SyncingFetchComplete: true, 39 | FetchingHead: t3, 40 | FetchingHeight: 789, 41 | } 42 | sr.UpdateStatus(validateHead(t1), validateHeight(1), syncingStarted(123), syncHead(t2), 43 | syncHeight(456), syncTrusted(true), syncComplete(false), syncFetchComplete(true), 44 | fetchHead(t3), fetchHeight(789)) 45 | assert.Equal(t, expStatus, sr.Status()) 46 | } 47 | -------------------------------------------------------------------------------- /chain/util.go: -------------------------------------------------------------------------------- 1 | package chain 2 | 3 | import ( 4 | "github.com/filecoin-project/go-filecoin/types" 5 | ) 6 | 7 | // Reverse reverses the order of the slice `chain`. 8 | func Reverse(chain []types.TipSet) { 9 | // https://github.com/golang/go/wiki/SliceTricks#reversing 10 | for i := len(chain)/2 - 1; i >= 0; i-- { 11 | opp := len(chain) - 1 - i 12 | chain[i], chain[opp] = chain[opp], chain[i] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /clock/clock.go: -------------------------------------------------------------------------------- 1 | package clock 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // Clock provides an interface that packages can use instead of directly 8 | // using the time module, so that chronology-related behavior can be tested 9 | // Adapted from: https://github.com/jonboulle/clockwork 10 | type Clock interface { 11 | After(d time.Duration) <-chan time.Time 12 | Sleep(d time.Duration) 13 | Now() time.Time 14 | Since(t time.Time) time.Duration 15 | 16 | NewTicker(d time.Duration) Ticker 17 | 18 | NewTimer(d time.Duration) Timer 19 | AfterFunc(d time.Duration, f func()) Timer 20 | } 21 | 22 | type realClock struct{} 23 | 24 | func (rc *realClock) After(d time.Duration) <-chan time.Time { 25 | return time.After(d) 26 | } 27 | 28 | func (rc *realClock) Sleep(d time.Duration) { 29 | time.Sleep(d) 30 | } 31 | 32 | func (rc *realClock) Now() time.Time { 33 | return time.Now() 34 | } 35 | 36 | func (rc *realClock) Since(t time.Time) time.Duration { 37 | return rc.Now().Sub(t) 38 | } 39 | 40 | func (rc *realClock) NewTicker(d time.Duration) Ticker { 41 | return &realTicker{time.NewTicker(d)} 42 | } 43 | 44 | func (rc *realClock) NewTimer(d time.Duration) Timer { 45 | return &realTimer{time.NewTimer(d)} 46 | } 47 | 48 | func (rc *realClock) AfterFunc(d time.Duration, f func()) Timer { 49 | return &realTimer{time.AfterFunc(d, f)} 50 | } 51 | 52 | // NewSystemClock returns a Clock that delegates calls to the actual time 53 | // package; it should be used by packages in production. 54 | func NewSystemClock() Clock { 55 | return &realClock{} 56 | } 57 | -------------------------------------------------------------------------------- /clock/ticker.go: -------------------------------------------------------------------------------- 1 | package clock 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // Ticker provides an interface which can be used instead of directly 8 | // using the ticker within the time module. The real-time ticker t 9 | // provides ticks through t.C which becomes now t.Chan() to make 10 | // this channel requirement definable in this interface. 11 | // Adapted from: https://github.com/jonboulle/clockwork 12 | type Ticker interface { 13 | Chan() <-chan time.Time 14 | Stop() 15 | } 16 | 17 | type realTicker struct{ *time.Ticker } 18 | 19 | func (rt *realTicker) Chan() <-chan time.Time { 20 | return rt.C 21 | } 22 | -------------------------------------------------------------------------------- /clock/timer.go: -------------------------------------------------------------------------------- 1 | package clock 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // Timer provides an interface to a time.Timer which is testable. 8 | // See https://golang.org/pkg/time/#Timer for more details on how timers work. 9 | type Timer interface { 10 | Chan() <-chan time.Time 11 | Reset(d time.Duration) bool 12 | Stop() bool 13 | } 14 | 15 | type realTimer struct { 16 | *time.Timer 17 | } 18 | 19 | func (rt *realTimer) Chan() <-chan time.Time { 20 | return rt.C 21 | } 22 | -------------------------------------------------------------------------------- /commands/actor_daemon_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | 11 | "github.com/filecoin-project/go-filecoin/commands" 12 | th "github.com/filecoin-project/go-filecoin/testhelpers" 13 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 14 | ) 15 | 16 | func TestActorDaemon(t *testing.T) { 17 | tf.IntegrationTest(t) 18 | 19 | t.Run("actor ls --enc json returns NDJSON containing all actors in the state tree", func(t *testing.T) { 20 | d := th.NewDaemon(t).Start() 21 | defer d.ShutdownSuccess() 22 | 23 | op1 := d.RunSuccess("actor", "ls", "--enc", "json") 24 | result1 := op1.ReadStdoutTrimNewlines() 25 | 26 | var avs []commands.ActorView 27 | for _, line := range bytes.Split([]byte(result1), []byte{'\n'}) { 28 | // unmarshall JSON to actor view an add to slice 29 | var av commands.ActorView 30 | err := json.Unmarshal(line, &av) 31 | require.NoError(t, err) 32 | avs = append(avs, av) 33 | } 34 | 35 | assert.NotZero(t, len(avs)) 36 | 37 | // The order of actors is consistent, but only within builds of genesis.car. 38 | // We just want to make sure the views have something valid in them. 39 | for _, av := range avs { 40 | assert.Contains(t, []string{"StoragemarketActor", "AccountActor", "PaymentbrokerActor", "MinerActor", "BootstrapMinerActor", "InitActor"}, av.ActorType) 41 | if av.ActorType == "AccountActor" { 42 | assert.Zero(t, len(av.Exports)) 43 | } else { 44 | assert.NotZero(t, len(av.Exports)) 45 | } 46 | } 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /commands/bitswap.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "github.com/ipfs/go-bitswap" 5 | "github.com/ipfs/go-ipfs-cmdkit" 6 | "github.com/ipfs/go-ipfs-cmds" 7 | ) 8 | 9 | var bitswapCmd = &cmds.Command{ 10 | Helptext: cmdkit.HelpText{ 11 | Tagline: "Explore libp2p bitswap.", 12 | }, 13 | 14 | Subcommands: map[string]*cmds.Command{ 15 | "stats": statsBitswapCmd, 16 | }, 17 | } 18 | 19 | var statsBitswapCmd = &cmds.Command{ 20 | Helptext: cmdkit.HelpText{ 21 | Tagline: "Show bitswap statistics.", 22 | }, 23 | 24 | Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { 25 | stats, err := GetPorcelainAPI(env).BitswapGetStats(req.Context) 26 | if err != nil { 27 | return err 28 | } 29 | return res.Emit(stats) 30 | }, 31 | Type: &bitswap.Stat{}, 32 | } 33 | -------------------------------------------------------------------------------- /commands/bitswap_stats_daemon_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "testing" 5 | 6 | th "github.com/filecoin-project/go-filecoin/testhelpers" 7 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestBitswapStats(t *testing.T) { 12 | tf.IntegrationTest(t) 13 | 14 | d := th.NewDaemon(t).Start() 15 | defer d.ShutdownSuccess() 16 | 17 | stats := d.RunSuccess("bitswap", "stats").ReadStdoutTrimNewlines() 18 | 19 | assert.Equal(t, `{"ProvideBufLen":0,"Wantlist":[],"Peers":[],"BlocksReceived":0,"DataReceived":0,"BlocksSent":0,"DataSent":0,"DupBlksReceived":0,"DupDataReceived":0,"MessagesReceived":0}`, stats) 20 | } 21 | -------------------------------------------------------------------------------- /commands/bootstrap.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | 7 | cmdkit "github.com/ipfs/go-ipfs-cmdkit" 8 | cmds "github.com/ipfs/go-ipfs-cmds" 9 | ) 10 | 11 | // BootstrapLsResult is the result of the bootstrap listing command. 12 | type BootstrapLsResult struct { 13 | Peers []string 14 | } 15 | 16 | var bootstrapCmd = &cmds.Command{ 17 | Helptext: cmdkit.HelpText{ 18 | Tagline: "Interact with bootstrap addresses", 19 | }, 20 | Subcommands: map[string]*cmds.Command{ 21 | "ls": bootstrapLsCmd, 22 | }, 23 | } 24 | 25 | var bootstrapLsCmd = &cmds.Command{ 26 | Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error { 27 | peers, err := GetPorcelainAPI(env).ConfigGet("bootstrap.addresses") 28 | if err != nil { 29 | return err 30 | } 31 | 32 | return re.Emit(&BootstrapLsResult{peers.([]string)}) 33 | }, 34 | Type: &BootstrapLsResult{}, 35 | Encoders: cmds.EncoderMap{ 36 | cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, br *BootstrapLsResult) error { 37 | _, err := fmt.Fprintln(w, br) 38 | return err 39 | }), 40 | }, 41 | } 42 | -------------------------------------------------------------------------------- /commands/bootstrap_daemon_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | th "github.com/filecoin-project/go-filecoin/testhelpers" 9 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 10 | ) 11 | 12 | func TestBootstrapList(t *testing.T) { 13 | tf.IntegrationTest(t) 14 | 15 | d := th.NewDaemon(t).Start() 16 | defer d.ShutdownSuccess() 17 | 18 | bs := d.RunSuccess("bootstrap ls") 19 | 20 | assert.Equal(t, "&{[]}\n", bs.ReadStdout()) 21 | } 22 | -------------------------------------------------------------------------------- /commands/commands_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/filecoin-project/go-filecoin/fixtures" 7 | th "github.com/filecoin-project/go-filecoin/testhelpers" 8 | ) 9 | 10 | // create a basic new TestDaemon, with a miner and the KeyInfo it needs to sign 11 | // tickets and blocks. This does not set a DefaultAddress in the Wallet; in this 12 | // case, node/init.go Init generates a new address in the wallet and sets it to 13 | // the default address. 14 | func makeTestDaemonWithMinerAndStart(t *testing.T) *th.TestDaemon { 15 | daemon := th.NewDaemon( 16 | t, 17 | th.WithMiner(fixtures.TestMiners[0]), 18 | th.KeyFile(fixtures.KeyFilePaths()[0]), 19 | ).Start() 20 | return daemon 21 | } 22 | -------------------------------------------------------------------------------- /commands/dag.go: -------------------------------------------------------------------------------- 1 | // Package commands implements the command to print the blockchain. 2 | package commands 3 | 4 | import ( 5 | cmdkit "github.com/ipfs/go-ipfs-cmdkit" 6 | cmds "github.com/ipfs/go-ipfs-cmds" 7 | ) 8 | 9 | var dagCmd = &cmds.Command{ 10 | Helptext: cmdkit.HelpText{ 11 | Tagline: "Interact with IPLD DAG objects.", 12 | }, 13 | Subcommands: map[string]*cmds.Command{ 14 | "get": dagGetCmd, 15 | }, 16 | } 17 | 18 | var dagGetCmd = &cmds.Command{ 19 | Helptext: cmdkit.HelpText{ 20 | Tagline: "Get a DAG node by its CID", 21 | }, 22 | Arguments: []cmdkit.Argument{ 23 | cmdkit.StringArg("ref", true, false, "CID of object to get"), 24 | }, 25 | Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error { 26 | out, err := GetPorcelainAPI(env).DAGGetNode(req.Context, req.Arguments[0]) 27 | if err != nil { 28 | return err 29 | } 30 | 31 | return re.Emit(out) 32 | }, 33 | } 34 | -------------------------------------------------------------------------------- /commands/dht_daemon_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "testing" 5 | 6 | ast "github.com/stretchr/testify/assert" 7 | 8 | th "github.com/filecoin-project/go-filecoin/testhelpers" 9 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 10 | ) 11 | 12 | func TestDhtFindPeer(t *testing.T) { 13 | tf.IntegrationTest(t) 14 | 15 | assert := ast.New(t) 16 | 17 | d1 := th.NewDaemon(t).Start() 18 | defer d1.ShutdownSuccess() 19 | 20 | d2 := th.NewDaemon(t).Start() 21 | defer d2.ShutdownSuccess() 22 | 23 | d1.ConnectSuccess(d2) 24 | 25 | d2Id := d2.GetID() 26 | 27 | findpeerOutput := d1.RunSuccess("dht", "findpeer", d2Id).ReadStdoutTrimNewlines() 28 | 29 | d2Addr := d2.GetAddresses()[0] 30 | 31 | assert.Contains(d2Addr, findpeerOutput) 32 | } 33 | 34 | // TODO: findprovs will have to be untested until 35 | // https://github.com/filecoin-project/go-filecoin/issues/2357 36 | // original tests were flaky; testing may need to be omitted entirely 37 | // unless it can consistently pass. 38 | -------------------------------------------------------------------------------- /commands/errors.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "fmt" 5 | "github.com/pkg/errors" 6 | ) 7 | 8 | var ( 9 | // ErrInvalidSize indicates that the provided size was invalid. 10 | ErrInvalidSize = fmt.Errorf("invalid size") 11 | 12 | // ErrInvalidPrice indicates that the provided price was invalid. 13 | ErrInvalidPrice = fmt.Errorf("invalid price") 14 | 15 | // ErrInvalidAmount indicates that the provided amount was invalid. 16 | ErrInvalidAmount = fmt.Errorf("invalid amount") 17 | 18 | // ErrInvalidCollateral indicates that provided collateral was invalid. 19 | ErrInvalidCollateral = fmt.Errorf("invalid collateral") 20 | 21 | // ErrInvalidPledge indicates that provided pledge was invalid. 22 | ErrInvalidPledge = fmt.Errorf("invalid pledge") 23 | 24 | // ErrInvalidBlockHeight indicates that the provided block height was invalid. 25 | ErrInvalidBlockHeight = fmt.Errorf("invalid block height") 26 | 27 | // ErrMissingDaemon is the error returned when trying to execute a command that requires the daemon to be started. 28 | ErrMissingDaemon = errors.New("daemon must be started before using this command") 29 | 30 | // ErrNoWalletAddresses indicates that there are no addresses in wallet to mine to. 31 | ErrNoWalletAddresses = fmt.Errorf("no addresses in wallet to mine to") 32 | ) 33 | -------------------------------------------------------------------------------- /commands/id_daemon_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "io/ioutil" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | 10 | th "github.com/filecoin-project/go-filecoin/testhelpers" 11 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 12 | ) 13 | 14 | func TestId(t *testing.T) { 15 | tf.IntegrationTest(t) 16 | 17 | d := th.NewDaemon(t).Start() 18 | defer d.ShutdownSuccess() 19 | 20 | id := d.RunSuccess("id") 21 | 22 | idContent := id.ReadStdout() 23 | assert.Containsf(t, idContent, "/ip4/127.0.0.1/tcp/", "default addr") 24 | assert.Contains(t, idContent, "ID") 25 | 26 | } 27 | 28 | func TestIdFormat(t *testing.T) { 29 | tf.IntegrationTest(t) 30 | 31 | d := th.NewDaemon(t).Start() 32 | defer d.ShutdownSuccess() 33 | 34 | idContent := d.RunSuccess("id", 35 | "--format=\"\\t\\t\\t\\n\"", 36 | ).ReadStdout() 37 | 38 | assert.Contains(t, idContent, "\t") 39 | assert.Contains(t, idContent, "\n") 40 | assert.Containsf(t, idContent, "/ip4/127.0.0.1/tcp/", "default addr") 41 | assert.NotContains(t, idContent, "ID") 42 | } 43 | 44 | func TestPersistId(t *testing.T) { 45 | tf.IntegrationTest(t) 46 | 47 | // we need to control this 48 | dir, err := ioutil.TempDir("", "go-fil-test") 49 | require.NoError(t, err) 50 | 51 | // Start a demon in dir 52 | d1 := th.NewDaemon(t, th.ContainerDir(dir)).Start() 53 | 54 | // get the id and kill it 55 | id1 := d1.GetID() 56 | d1.Stop() 57 | 58 | // restart the daemon 59 | d2 := th.NewDaemon(t, th.ShouldInit(false), th.ContainerDir(dir)).Start() 60 | 61 | // get the id and compare to previous 62 | id2 := d2.GetID() 63 | d2.ShutdownSuccess() 64 | t.Logf("d1: %s", d1.ReadStdout()) 65 | t.Logf("d2: %s", d2.ReadStdout()) 66 | assert.Equal(t, id1, id2) 67 | } 68 | -------------------------------------------------------------------------------- /commands/init_daemon_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | "os/exec" 8 | "strconv" 9 | "testing" 10 | 11 | manet "github.com/multiformats/go-multiaddr-net" 12 | "github.com/stretchr/testify/require" 13 | 14 | th "github.com/filecoin-project/go-filecoin/testhelpers" 15 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 16 | ) 17 | 18 | func TestInitOverHttp(t *testing.T) { 19 | tf.IntegrationTest(t) 20 | 21 | td := th.NewDaemon(t).Start() 22 | defer td.ShutdownSuccess() 23 | 24 | maddr, err := td.CmdAddr() 25 | require.NoError(t, err) 26 | 27 | _, host, err := manet.DialArgs(maddr) 28 | require.NoError(t, err) 29 | 30 | url := fmt.Sprintf("http://%s/api/init", host) 31 | req, err := http.NewRequest("POST", url, nil) 32 | require.NoError(t, err) 33 | res, err := http.DefaultClient.Do(req) 34 | require.NoError(t, err) 35 | require.Equal(t, http.StatusNotFound, res.StatusCode) 36 | } 37 | 38 | func TestDownloadGenesis(t *testing.T) { 39 | tf.IntegrationTest(t) 40 | 41 | ctx, cancel := context.WithCancel(context.Background()) 42 | defer cancel() 43 | 44 | port, err := th.GetFreePort() 45 | require.NoError(t, err) 46 | 47 | err = exec.CommandContext( 48 | ctx, 49 | th.ProjectRoot("tools/genesis-file-server/genesis-file-server"), 50 | "--genesis-file-path", 51 | th.ProjectRoot("fixtures/test/genesis.car"), 52 | "--port", 53 | strconv.Itoa(port), 54 | ).Start() 55 | require.NoError(t, err) 56 | 57 | td := th.NewDaemon(t, th.GenesisFile(fmt.Sprintf("http://127.0.0.1:%d/genesis.car", port))).Start() 58 | 59 | td.ShutdownSuccess() 60 | } 61 | -------------------------------------------------------------------------------- /commands/inspector_daemon_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | 10 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 11 | "github.com/filecoin-project/go-filecoin/tools/fast" 12 | "github.com/filecoin-project/go-filecoin/tools/fast/fastesting" 13 | ) 14 | 15 | func TestInspectConfig(t *testing.T) { 16 | tf.IntegrationTest(t) 17 | 18 | ctx, env := fastesting.NewTestEnvironment(context.Background(), t, fast.FilecoinOpts{}) 19 | 20 | // Teardown after test ends 21 | defer func() { 22 | err := env.Teardown(ctx) 23 | require.NoError(t, err) 24 | }() 25 | 26 | nd := env.RequireNewNodeStarted() 27 | 28 | icfg, err := nd.InspectConfig(ctx) 29 | require.NoError(t, err) 30 | 31 | rcfg, err := nd.Config() 32 | require.NoError(t, err) 33 | 34 | // API is not the same since the FAST plugin reads the config file from disk, 35 | // this is a limitation of FAST. 36 | // FAST sets API.Address to /ip4/0.0.0.0/0 in the config file to avoid port collisions. 37 | // The Inspector returns an in memory representation of the config that has 38 | // received a port assignment from the kernel, meaning it is no longer /ip4/0.0.0.0/0 39 | assert.Equal(t, rcfg.Bootstrap, icfg.Bootstrap) 40 | assert.Equal(t, rcfg.Datastore, icfg.Datastore) 41 | assert.Equal(t, rcfg.Swarm, icfg.Swarm) 42 | assert.Equal(t, rcfg.Mining, icfg.Mining) 43 | assert.Equal(t, rcfg.Wallet, icfg.Wallet) 44 | assert.Equal(t, rcfg.Heartbeat, icfg.Heartbeat) 45 | assert.Equal(t, rcfg.Mpool, icfg.Mpool) 46 | } 47 | -------------------------------------------------------------------------------- /commands/inspector_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "runtime" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | 9 | "github.com/filecoin-project/go-filecoin/commands" 10 | "github.com/filecoin-project/go-filecoin/config" 11 | "github.com/filecoin-project/go-filecoin/repo" 12 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 13 | ) 14 | 15 | func TestRuntime(t *testing.T) { 16 | tf.UnitTest(t) 17 | 18 | mr := repo.NewInMemoryRepo() 19 | g := commands.NewInspectorAPI(mr) 20 | rt := g.Runtime() 21 | 22 | assert.Equal(t, runtime.GOOS, rt.OS) 23 | assert.Equal(t, runtime.GOARCH, rt.Arch) 24 | assert.Equal(t, runtime.Version(), rt.Version) 25 | assert.Equal(t, runtime.Compiler, rt.Compiler) 26 | assert.Equal(t, runtime.NumCPU(), rt.NumProc) 27 | assert.Equal(t, runtime.GOMAXPROCS(0), rt.GoMaxProcs) 28 | assert.Equal(t, runtime.NumCgoCall(), rt.NumCGoCalls) 29 | } 30 | 31 | func TestDisk(t *testing.T) { 32 | tf.UnitTest(t) 33 | 34 | mr := repo.NewInMemoryRepo() 35 | g := commands.NewInspectorAPI(mr) 36 | d, err := g.Disk() 37 | 38 | assert.NoError(t, err) 39 | assert.Equal(t, uint64(0), d.Free) 40 | assert.Equal(t, uint64(0), d.Total) 41 | assert.Equal(t, "0", d.FSType) 42 | } 43 | 44 | func TestMemory(t *testing.T) { 45 | tf.UnitTest(t) 46 | 47 | mr := repo.NewInMemoryRepo() 48 | g := commands.NewInspectorAPI(mr) 49 | 50 | _, err := g.Memory() 51 | assert.NoError(t, err) 52 | } 53 | 54 | func TestConfig(t *testing.T) { 55 | tf.UnitTest(t) 56 | 57 | mr := repo.NewInMemoryRepo() 58 | g := commands.NewInspectorAPI(mr) 59 | c := g.Config() 60 | assert.Equal(t, config.NewDefaultConfig(), c) 61 | } 62 | -------------------------------------------------------------------------------- /commands/leb128_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | 8 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 9 | ) 10 | 11 | func TestLeb128Decode(t *testing.T) { 12 | tf.IntegrationTest(t) 13 | 14 | decodeTests := []struct { 15 | Text string 16 | Want string 17 | }{ 18 | {"A==", "65"}, 19 | } 20 | 21 | d := makeTestDaemonWithMinerAndStart(t) 22 | defer d.ShutdownSuccess() 23 | 24 | for _, tt := range decodeTests { 25 | output := d.RunSuccess("leb128", "decode", tt.Text).ReadStdoutTrimNewlines() 26 | 27 | require.Equal(t, tt.Want, output) 28 | } 29 | } 30 | 31 | func TestLeb128Encode(t *testing.T) { 32 | tf.IntegrationTest(t) 33 | 34 | encodeTests := []struct { 35 | Text string 36 | Want string 37 | }{ 38 | {"65", "A=="}, 39 | } 40 | 41 | d := makeTestDaemonWithMinerAndStart(t) 42 | defer d.ShutdownSuccess() 43 | 44 | for _, tt := range encodeTests { 45 | output := d.RunSuccess("leb128", "encode", tt.Text).ReadStdoutTrimNewlines() 46 | 47 | require.Contains(t, output, tt.Want) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /commands/main_daemon_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "os" 5 | "os/exec" 6 | "path" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | 12 | "github.com/filecoin-project/go-filecoin/testhelpers" 13 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 14 | ) 15 | 16 | func TestNoDaemonNoHang(t *testing.T) { 17 | tf.IntegrationTest(t) 18 | 19 | // Start the daemon to initialize a new repo 20 | d := testhelpers.NewDaemon(t).Start() 21 | 22 | // rename the lock files to a safe place 23 | repoDir := d.RepoDir() 24 | require.NoError(t, os.Rename(path.Join(repoDir, "api"), path.Join(repoDir, "api.backup"))) 25 | require.NoError(t, os.Rename(path.Join(repoDir, "repo.lock"), path.Join(repoDir, "repo.lock.backup"))) 26 | 27 | // shut down the daemon 28 | d.Stop() 29 | 30 | // put the lock files back 31 | require.NoError(t, os.Rename(path.Join(repoDir, "api.backup"), path.Join(repoDir, "api"))) 32 | require.NoError(t, os.Rename(path.Join(repoDir, "repo.lock.backup"), path.Join(repoDir, "repo.lock"))) 33 | 34 | // run actor ls with the old repo that still has the lock file, but no running daemon 35 | out, _ := exec.Command(testhelpers.MustGetFilecoinBinary(), "--repodir", d.RepoDir(), "actor", "ls").CombinedOutput() 36 | 37 | assert.Contains(t, string(out), "Is the daemon running?") 38 | } 39 | -------------------------------------------------------------------------------- /commands/main_test.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 8 | "github.com/ipfs/go-ipfs-cmds" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestRequiresDaemon(t *testing.T) { 13 | tf.UnitTest(t) 14 | 15 | reqWithDaemon, err := cmds.NewRequest(context.Background(), []string{"chain", "head"}, nil, []string{}, nil, rootCmdDaemon) 16 | assert.NoError(t, err) 17 | assert.True(t, requiresDaemon(reqWithDaemon)) 18 | 19 | reqWithoutDaemon, err := cmds.NewRequest(context.Background(), []string{"daemon"}, nil, []string{}, nil, rootCmd) 20 | assert.NoError(t, err) 21 | assert.False(t, requiresDaemon(reqWithoutDaemon)) 22 | 23 | reqSubcmdDaemon, err := cmds.NewRequest(context.Background(), []string{"leb128", "decode"}, nil, []string{"A=="}, nil, rootCmd) 24 | assert.NoError(t, err) 25 | assert.False(t, requiresDaemon(reqSubcmdDaemon)) 26 | } 27 | -------------------------------------------------------------------------------- /commands/ping_daemon_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | 9 | "github.com/filecoin-project/go-filecoin/node" 10 | "github.com/filecoin-project/go-filecoin/node/test" 11 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 12 | ) 13 | 14 | func TestPing2Nodes(t *testing.T) { 15 | tf.IntegrationTest(t) 16 | 17 | ctx := context.Background() 18 | builder := test.NewNodeBuilder(t) 19 | 20 | n1 := builder.BuildAndStart(ctx) 21 | n2 := builder.BuildAndStart(ctx) 22 | defer n1.Stop(ctx) 23 | defer n2.Stop(ctx) 24 | 25 | // The node are not initially connected, so ping should fail. 26 | res0, err := n1.PorcelainAPI.NetworkPing(ctx, n2.Network.PeerHost.ID()) 27 | assert.NoError(t, err) 28 | assert.Error(t, (<-res0).Error) // No peers in table 29 | 30 | // Connect nodes and check each can ping the other. 31 | node.ConnectNodes(t, n1, n2) 32 | 33 | res1, err := n1.PorcelainAPI.NetworkPing(ctx, n2.Network.PeerHost.ID()) 34 | assert.NoError(t, err) 35 | assert.NoError(t, (<-res1).Error) 36 | 37 | res2, err := n2.PorcelainAPI.NetworkPing(ctx, n1.Network.PeerHost.ID()) 38 | assert.NoError(t, err) 39 | assert.NoError(t, (<-res2).Error) 40 | } 41 | -------------------------------------------------------------------------------- /commands/protocol.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | 7 | "github.com/ipfs/go-ipfs-cmdkit" 8 | "github.com/ipfs/go-ipfs-cmds" 9 | 10 | "github.com/filecoin-project/go-filecoin/porcelain" 11 | ) 12 | 13 | var protocolCmd = &cmds.Command{ 14 | Helptext: cmdkit.HelpText{ 15 | Tagline: "Show protocol parameter details", 16 | }, 17 | Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error { 18 | params, err := GetPorcelainAPI(env).ProtocolParameters(env.Context()) 19 | if err != nil { 20 | return err 21 | } 22 | return re.Emit(params) 23 | }, 24 | Type: porcelain.ProtocolParams{}, 25 | Encoders: cmds.EncoderMap{ 26 | cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, pp *porcelain.ProtocolParams) error { 27 | _, err := fmt.Fprintf(w, "Network: %s\n", pp.Network) 28 | if err != nil { 29 | return err 30 | } 31 | 32 | _, err = fmt.Fprintf(w, "Auto-Seal Interval: %d seconds\nSector Sizes:\n", pp.AutoSealInterval) 33 | if err != nil { 34 | return err 35 | } 36 | 37 | for _, sectorInfo := range pp.SupportedSectors { 38 | _, err = fmt.Fprintf(w, "\t%s (%s writeable)\n", readableBytesAmount(float64(sectorInfo.Size.Uint64())), readableBytesAmount(float64(sectorInfo.MaxPieceSize.Uint64()))) 39 | if err != nil { 40 | return err 41 | } 42 | } 43 | 44 | return nil 45 | }), 46 | }, 47 | } 48 | 49 | func readableBytesAmount(amt float64) string { 50 | unit := 0 51 | units := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"} 52 | 53 | for amt >= 1024 && unit < len(units)-1 { 54 | amt /= 1024 55 | unit++ 56 | } 57 | 58 | return fmt.Sprintf("%.2f %s", amt, units[unit]) 59 | } 60 | -------------------------------------------------------------------------------- /commands/protocol_cmd_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | 10 | "github.com/filecoin-project/go-filecoin/config" 11 | "github.com/filecoin-project/go-filecoin/node/test" 12 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 13 | ) 14 | 15 | func TestProtocol(t *testing.T) { 16 | tf.IntegrationTest(t) 17 | ctx := context.Background() 18 | 19 | // Create node (it's not necessary to start it). 20 | b := test.NewNodeBuilder(t) 21 | node := b. 22 | WithConfig(func(c *config.Config) { 23 | c.Mining.AutoSealIntervalSeconds = 120 24 | }). 25 | Build(ctx) 26 | require.NoError(t, node.Chain.ChainReader.Load(ctx)) 27 | 28 | // Run the command API. 29 | cmd, stop := test.RunNodeAPI(ctx, node, t) 30 | defer stop() 31 | 32 | out := cmd.RunSuccess(ctx, "protocol").ReadStdout() 33 | assert.Contains(t, out, "Network: go-filecoin-test") 34 | assert.Contains(t, out, "Auto-Seal Interval: 120 seconds") 35 | } 36 | -------------------------------------------------------------------------------- /commands/retrieval_client.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "github.com/ipfs/go-cid" 5 | "github.com/ipfs/go-ipfs-cmdkit" 6 | "github.com/ipfs/go-ipfs-cmds" 7 | 8 | "github.com/filecoin-project/go-filecoin/address" 9 | ) 10 | 11 | var retrievalClientCmd = &cmds.Command{ 12 | Helptext: cmdkit.HelpText{ 13 | Tagline: "Manage retrieval client operations", 14 | }, 15 | Subcommands: map[string]*cmds.Command{ 16 | "retrieve-piece": clientRetrievePieceCmd, 17 | }, 18 | } 19 | 20 | var clientRetrievePieceCmd = &cmds.Command{ 21 | Helptext: cmdkit.HelpText{ 22 | Tagline: "Read out piece data stored by a miner on the network", 23 | }, 24 | Arguments: []cmdkit.Argument{ 25 | cmdkit.StringArg("miner", true, false, "Retrieval miner actor address"), 26 | cmdkit.StringArg("cid", true, false, "Content identifier of piece to read"), 27 | }, 28 | Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error { 29 | minerAddr, err := address.NewFromString(req.Arguments[0]) 30 | if err != nil { 31 | return err 32 | } 33 | 34 | pieceCID, err := cid.Decode(req.Arguments[1]) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | mpid, err := GetPorcelainAPI(env).MinerGetPeerID(req.Context, minerAddr) 40 | if err != nil { 41 | return err 42 | } 43 | 44 | readCloser, err := GetRetrievalAPI(env).RetrievePiece(req.Context, pieceCID, mpid, minerAddr) 45 | if err != nil { 46 | return err 47 | } 48 | 49 | return re.Emit(readCloser) 50 | }, 51 | } 52 | -------------------------------------------------------------------------------- /commands/stats.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "github.com/ipfs/go-ipfs-cmdkit" 5 | "github.com/ipfs/go-ipfs-cmds" 6 | "github.com/libp2p/go-libp2p-core/metrics" 7 | ) 8 | 9 | var statsCmd = &cmds.Command{ 10 | Helptext: cmdkit.HelpText{ 11 | Tagline: "View various filecoin node statistics", 12 | }, 13 | Subcommands: map[string]*cmds.Command{ 14 | "bandwidth": statsBandwidthCmd, 15 | }, 16 | } 17 | 18 | var statsBandwidthCmd = &cmds.Command{ 19 | Helptext: cmdkit.HelpText{ 20 | Tagline: "View bandwidth usage metrics", 21 | }, 22 | Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error { 23 | bandwidthStats := GetPorcelainAPI(env).NetworkGetBandwidthStats() 24 | 25 | return re.Emit(bandwidthStats) 26 | }, 27 | Type: metrics.Stats{}, 28 | } 29 | -------------------------------------------------------------------------------- /commands/stats_daemon_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | th "github.com/filecoin-project/go-filecoin/testhelpers" 9 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 10 | ) 11 | 12 | func TestStatsBandwidth(t *testing.T) { 13 | tf.IntegrationTest(t) 14 | 15 | d := th.NewDaemon(t).Start() 16 | defer d.ShutdownSuccess() 17 | 18 | stats := d.RunSuccess("stats", "bandwidth").ReadStdoutTrimNewlines() 19 | 20 | assert.Equal(t, "{\"TotalIn\":0,\"TotalOut\":0,\"RateIn\":0,\"RateOut\":0}", stats) 21 | } 22 | -------------------------------------------------------------------------------- /commands/swarm_daemon_test.go: -------------------------------------------------------------------------------- 1 | package commands_test 2 | 3 | import ( 4 | "testing" 5 | 6 | th "github.com/filecoin-project/go-filecoin/testhelpers" 7 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 8 | ) 9 | 10 | func TestSwarmConnectPeersValid(t *testing.T) { 11 | tf.IntegrationTest(t) 12 | 13 | d1 := th.NewDaemon(t).Start() 14 | defer d1.ShutdownSuccess() 15 | 16 | d2 := th.NewDaemon(t).Start() 17 | defer d2.ShutdownSuccess() 18 | 19 | d1.ConnectSuccess(d2) 20 | } 21 | 22 | func TestSwarmConnectPeersInvalid(t *testing.T) { 23 | tf.IntegrationTest(t) 24 | 25 | d1 := th.NewDaemon(t).Start() 26 | defer d1.ShutdownSuccess() 27 | 28 | d1.RunFail("failed to parse ip4 addr", 29 | "swarm connect /ip4/hello", 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /commands/util_test.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ipfs/go-ipfs-cmdkit" 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | 10 | "github.com/filecoin-project/go-filecoin/address" 11 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 12 | ) 13 | 14 | func TestOptionalAddr(t *testing.T) { 15 | tf.UnitTest(t) 16 | 17 | t.Run("when option is specified", func(t *testing.T) { 18 | 19 | opts := make(cmdkit.OptMap) 20 | 21 | specifiedAddr, err := address.NewActorAddress([]byte("a new test address")) 22 | require.NoError(t, err) 23 | opts["from"] = specifiedAddr.String() 24 | 25 | addr, err := optionalAddr(opts["from"]) 26 | require.NoError(t, err) 27 | assert.Equal(t, specifiedAddr, addr) 28 | }) 29 | 30 | t.Run("when no option specified return empty", func(t *testing.T) { 31 | 32 | opts := make(cmdkit.OptMap) 33 | 34 | addr, err := optionalAddr(opts["from"]) 35 | require.NoError(t, err) 36 | assert.Equal(t, address.Undef, addr) 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /commands/version.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | 7 | cmdkit "github.com/ipfs/go-ipfs-cmdkit" 8 | cmds "github.com/ipfs/go-ipfs-cmds" 9 | 10 | "github.com/filecoin-project/go-filecoin/flags" 11 | ) 12 | 13 | type versionInfo struct { 14 | // Commit, is the git sha that was used to build this version of go-filecoin. 15 | Commit string 16 | } 17 | 18 | var versionCmd = &cmds.Command{ 19 | Helptext: cmdkit.HelpText{ 20 | Tagline: "Show go-filecoin version information", 21 | }, 22 | Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error { 23 | return re.Emit(&versionInfo{ 24 | Commit: flags.Commit, 25 | }) 26 | }, 27 | Type: versionInfo{}, 28 | Encoders: cmds.EncoderMap{ 29 | cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, vo *versionInfo) error { 30 | _, err := fmt.Fprintf(w, "commit: %s\n", vo.Commit) 31 | return err 32 | }), 33 | }, 34 | } 35 | -------------------------------------------------------------------------------- /fixtures/live/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirmaChain/go-filecoin/4fcb713a209be0efac91da709cabbcfe89ceee7c/fixtures/live/.gitkeep -------------------------------------------------------------------------------- /fixtures/setup.json: -------------------------------------------------------------------------------- 1 | { 2 | "keys": 5, 3 | "preAlloc": [ 4 | "1000000000000", 5 | "1000000000000", 6 | "1000000000000", 7 | "1000000000000", 8 | "1000000000000" 9 | ], 10 | "miners": [{ 11 | "owner": 0, 12 | "numCommittedSectors": 1 13 | }], 14 | "network": "go-filecoin-test" 15 | } 16 | -------------------------------------------------------------------------------- /fixtures/test/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirmaChain/go-filecoin/4fcb713a209be0efac91da709cabbcfe89ceee7c/fixtures/test/.gitkeep -------------------------------------------------------------------------------- /flags/flags.go: -------------------------------------------------------------------------------- 1 | package flags 2 | 3 | // Commit is the current git commit, injected through ldflags. 4 | var Commit string 5 | -------------------------------------------------------------------------------- /functional-tests/network-deployment/logging_test.go: -------------------------------------------------------------------------------- 1 | package networkdeployment_test 2 | 3 | import ( 4 | logging "github.com/ipfs/go-log" 5 | oldlogging "github.com/whyrusleeping/go-logging" 6 | ) 7 | 8 | func init() { 9 | logging.SetAllLoggers(oldlogging.INFO) 10 | } 11 | -------------------------------------------------------------------------------- /functional-tests/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" 7 | 8 | # Go tests 9 | go test -v "./$(basename $DIR)/..." -functional 10 | 11 | # Shell Tests 12 | . $DIR/retrieval 13 | 14 | 15 | -------------------------------------------------------------------------------- /issue_template.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | ### Acceptance criteria 4 | 5 | ### Risks + pitfalls 6 | 7 | ### Protocol Changes 8 | 9 | ### Where to begin 10 | -------------------------------------------------------------------------------- /message/handler.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/pkg/errors" 7 | 8 | "github.com/filecoin-project/go-filecoin/chain" 9 | "github.com/filecoin-project/go-filecoin/types" 10 | ) 11 | 12 | // HeadHandler wires up new head tipset handling to the message inbox and outbox. 13 | type HeadHandler struct { 14 | // Inbox and outbox exported for testing. 15 | Inbox *Inbox 16 | Outbox *Outbox 17 | chain chainProvider 18 | 19 | prevHead types.TipSet 20 | } 21 | 22 | // NewHeadHandler build a new new-head handler. 23 | func NewHeadHandler(inbox *Inbox, outbox *Outbox, chain chainProvider, head types.TipSet) *HeadHandler { 24 | return &HeadHandler{inbox, outbox, chain, head} 25 | } 26 | 27 | // HandleNewHead computes the chain delta implied by a new head and updates the inbox and outbox. 28 | func (h *HeadHandler) HandleNewHead(ctx context.Context, newHead types.TipSet) error { 29 | if !newHead.Defined() { 30 | log.Warning("received empty tipset, ignoring") 31 | return nil 32 | } 33 | if newHead.Equals(h.prevHead) { 34 | log.Warningf("received non-new head tipset, ignoring %s", newHead.Key()) 35 | return nil 36 | } 37 | 38 | oldTips, newTips, err := chain.CollectTipsToCommonAncestor(ctx, h.chain, h.prevHead, newHead) 39 | if err != nil { 40 | return errors.Errorf("traversing chain with new head %s, prev %s: %s", newHead.Key(), h.prevHead.Key(), err) 41 | } 42 | if err := h.Outbox.HandleNewHead(ctx, oldTips, newTips); err != nil { 43 | log.Errorf("updating outbound message queue for tipset %s, prev %s: %s", newHead.Key(), h.prevHead.Key(), err) 44 | } 45 | if err := h.Inbox.HandleNewHead(ctx, oldTips, newTips); err != nil { 46 | log.Errorf("updating message pool for tipset %s, prev %s: %s", newHead.Key(), h.prevHead.Key(), err) 47 | } 48 | 49 | h.prevHead = newHead 50 | return nil 51 | } 52 | -------------------------------------------------------------------------------- /message/publisher.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/pkg/errors" 7 | 8 | "github.com/filecoin-project/go-filecoin/types" 9 | ) 10 | 11 | // DefaultPublisher adds messages to a message pool and can publish them to its topic. 12 | // This is wiring for message publication from the outbox. 13 | type DefaultPublisher struct { 14 | network networkPublisher 15 | topic string 16 | pool *Pool 17 | } 18 | 19 | type networkPublisher interface { 20 | Publish(topic string, data []byte) error 21 | } 22 | 23 | // NewDefaultPublisher creates a new publisher. 24 | func NewDefaultPublisher(pubsub networkPublisher, topic string, pool *Pool) *DefaultPublisher { 25 | return &DefaultPublisher{pubsub, topic, pool} 26 | } 27 | 28 | // Publish marshals and publishes a message to the core message pool, and if bcast is true, 29 | // broadcasts it to the network with the publisher's topic. 30 | func (p *DefaultPublisher) Publish(ctx context.Context, message *types.SignedMessage, height uint64, bcast bool) error { 31 | encoded, err := message.Marshal() 32 | if err != nil { 33 | return errors.Wrap(err, "failed to marshal message") 34 | } 35 | 36 | if _, err := p.pool.Add(ctx, message, height); err != nil { 37 | return errors.Wrap(err, "failed to add message to message pool") 38 | } 39 | 40 | if bcast { 41 | if err = p.network.Publish(p.topic, encoded); err != nil { 42 | return errors.Wrap(err, "failed to publish message to network") 43 | } 44 | } 45 | return nil 46 | } 47 | -------------------------------------------------------------------------------- /message/publisher_test.go: -------------------------------------------------------------------------------- 1 | package message_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | 10 | "github.com/filecoin-project/go-filecoin/config" 11 | "github.com/filecoin-project/go-filecoin/message" 12 | "github.com/filecoin-project/go-filecoin/testhelpers" 13 | "github.com/filecoin-project/go-filecoin/types" 14 | ) 15 | 16 | func TestDefaultMessagePublisher_Publish(t *testing.T) { 17 | pool := message.NewPool(config.NewDefaultConfig().Mpool, testhelpers.NewMockMessagePoolValidator()) 18 | 19 | ms, _ := types.NewMockSignersAndKeyInfo(2) 20 | msg := types.NewMessage(ms.Addresses[0], ms.Addresses[1], 0, types.ZeroAttoFIL, "", []byte{}) 21 | signed, err := types.NewSignedMessage(*msg, ms, types.ZeroAttoFIL, types.NewGasUnits(0)) 22 | require.NoError(t, err) 23 | msgCid, err := signed.Cid() 24 | require.NoError(t, err) 25 | encoded, e := signed.Marshal() 26 | require.NoError(t, e) 27 | 28 | testCases := []struct { 29 | name string 30 | bcast bool 31 | }{ 32 | {"Msg added to pool and Publish is called when bcast is true", true}, 33 | {"Msg added to pool and Publish is NOT called when bcast is false", false}, 34 | } 35 | 36 | for _, test := range testCases { 37 | t.Run(test.name, func(t *testing.T) { 38 | mnp := message.MockNetworkPublisher{} 39 | pub := message.NewDefaultPublisher(&mnp, "Topic", pool) 40 | assert.NoError(t, pub.Publish(context.Background(), signed, 0, test.bcast)) 41 | smsg, ok := pool.Get(msgCid) 42 | assert.True(t, ok) 43 | assert.NotNil(t, smsg) 44 | if test.bcast { 45 | assert.Equal(t, "Topic", mnp.Topic) 46 | assert.Equal(t, encoded, mnp.Data) 47 | } else { 48 | assert.Equal(t, "", mnp.Topic) 49 | assert.Nil(t, mnp.Data) 50 | } 51 | }) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /message/util.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "github.com/filecoin-project/go-filecoin/chain" 5 | "github.com/filecoin-project/go-filecoin/types" 6 | ) 7 | 8 | // chainProvider provides chain access for updating the message pool in response to new heads. 9 | type chainProvider interface { 10 | // The TipSetProvider is used only for counting non-null tipsets when expiring messages. We could remove 11 | // this dependency if expiration was based on round number, or if this object maintained a short 12 | // list of non-empty tip heights. 13 | chain.TipSetProvider 14 | GetHead() types.TipSetKey 15 | } 16 | -------------------------------------------------------------------------------- /metrics/counter.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import ( 4 | "context" 5 | 6 | "go.opencensus.io/stats" 7 | "go.opencensus.io/stats/view" 8 | ) 9 | 10 | // Int64Counter wraps an opencensus int64 measure that is uses as a counter. 11 | type Int64Counter struct { 12 | measureCt *stats.Int64Measure 13 | view *view.View 14 | } 15 | 16 | // NewInt64Counter creates a new Int64Counter with demensionless units. 17 | func NewInt64Counter(name, desc string) *Int64Counter { 18 | log.Infof("registering int64 counter: %s - %s", name, desc) 19 | iMeasure := stats.Int64(name, desc, stats.UnitDimensionless) 20 | iView := &view.View{ 21 | Name: name, 22 | Measure: iMeasure, 23 | Description: desc, 24 | Aggregation: view.Count(), 25 | } 26 | if err := view.Register(iView); err != nil { 27 | // a panic here indicates a developer error when creating a view. 28 | // Since this method is called in init() methods, this panic when hit 29 | // will cause running the program to fail immediately. 30 | panic(err) 31 | } 32 | 33 | return &Int64Counter{ 34 | measureCt: iMeasure, 35 | view: iView, 36 | } 37 | } 38 | 39 | // Inc increments the counter by value `v`. 40 | func (c *Int64Counter) Inc(ctx context.Context, v int64) { 41 | stats.Record(ctx, c.measureCt.M(v)) 42 | } 43 | -------------------------------------------------------------------------------- /metrics/gauge.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import ( 4 | "context" 5 | 6 | "go.opencensus.io/stats" 7 | "go.opencensus.io/stats/view" 8 | "go.opencensus.io/tag" 9 | ) 10 | 11 | // Int64Gauge wraps an opencensus int64 measure that is uses as a gauge. 12 | type Int64Gauge struct { 13 | measureCt *stats.Int64Measure 14 | view *view.View 15 | } 16 | 17 | // NewInt64Gauge creates a new Int64Gauge with demensionless units. 18 | func NewInt64Gauge(name, desc string, keys ...tag.Key) *Int64Gauge { 19 | log.Infof("registering int64 gauge: %s - %s", name, desc) 20 | iMeasure := stats.Int64(name, desc, stats.UnitDimensionless) 21 | 22 | iView := &view.View{ 23 | Name: name, 24 | Measure: iMeasure, 25 | Description: desc, 26 | Aggregation: view.LastValue(), 27 | TagKeys: keys, 28 | } 29 | if err := view.Register(iView); err != nil { 30 | // a panic here indicates a developer error when creating a view. 31 | // Since this method is called in init() methods, this panic when hit 32 | // will cause running the program to fail immediately. 33 | panic(err) 34 | } 35 | 36 | return &Int64Gauge{ 37 | measureCt: iMeasure, 38 | view: iView, 39 | } 40 | } 41 | 42 | // Set sets the value of the gauge to value `v`. 43 | func (c *Int64Gauge) Set(ctx context.Context, v int64) { 44 | stats.Record(ctx, c.measureCt.M(v)) 45 | } 46 | -------------------------------------------------------------------------------- /metrics/log_json_formatter.go: -------------------------------------------------------------------------------- 1 | package metrics 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io" 7 | "path/filepath" 8 | "runtime" 9 | "time" 10 | 11 | oldlogging "github.com/whyrusleeping/go-logging" 12 | ) 13 | 14 | // JSONFormatter implements go-logging Formatter for JSON encoded logs 15 | type JSONFormatter struct { 16 | } 17 | 18 | type logRecord struct { 19 | Timestamp time.Time `json:"timestamp"` 20 | Level string `json:"level"` 21 | System string `json:"system"` 22 | Message string `json:"message"` 23 | File string `json:"file"` 24 | } 25 | 26 | // Format implements go-logging Formatter 27 | func (jf *JSONFormatter) Format(calldepth int, r *oldlogging.Record, w io.Writer) error { 28 | var fileLine string 29 | if calldepth > 0 { 30 | _, file, line, ok := runtime.Caller(calldepth + 1) 31 | if !ok { 32 | fileLine = "???:0" 33 | } else { 34 | fileLine = fmt.Sprintf("%s:%d", filepath.Base(file), line) 35 | } 36 | } 37 | lr := &logRecord{ 38 | Timestamp: r.Time, 39 | Level: r.Level.String(), 40 | System: r.Module, 41 | Message: r.Message(), 42 | File: fileLine, 43 | } 44 | encoder := json.NewEncoder(w) 45 | return encoder.Encode(lr) 46 | } 47 | -------------------------------------------------------------------------------- /metrics/tracing/util.go: -------------------------------------------------------------------------------- 1 | package tracing 2 | 3 | import ( 4 | "context" 5 | 6 | "go.opencensus.io/trace" 7 | ) 8 | 9 | // AddErrorEndSpan will end `span` and adds `err` to `span` iff err is not nil. 10 | // This is a helper method to cut down on boiler plate. 11 | func AddErrorEndSpan(ctx context.Context, span *trace.Span, err *error) { 12 | if *err != nil { 13 | span.AddAttributes(trace.StringAttribute("error", (*err).Error())) 14 | } 15 | span.End() 16 | } 17 | -------------------------------------------------------------------------------- /net/address.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | import ( 4 | "github.com/libp2p/go-libp2p-core/peer" 5 | ma "github.com/multiformats/go-multiaddr" 6 | ) 7 | 8 | // PeerAddrsToAddrInfo converts a slice of string peer addresses 9 | // (multiaddr + ipfs peerid) to PeerInfos. 10 | func PeerAddrsToAddrInfo(addrs []string) ([]peer.AddrInfo, error) { 11 | var pis []peer.AddrInfo 12 | for _, addr := range addrs { 13 | a, err := ma.NewMultiaddr(addr) 14 | if err != nil { 15 | return nil, err 16 | } 17 | 18 | pinfo, err := peer.AddrInfoFromP2pAddr(a) 19 | if err != nil { 20 | return nil, err 21 | } 22 | pis = append(pis, *pinfo) 23 | } 24 | return pis, nil 25 | } 26 | 27 | // AddrInfoToPeerIDs converts a slice of AddrInfo to a slice of peerID's. 28 | func AddrInfoToPeerIDs(ai []peer.AddrInfo) []peer.ID { 29 | var pis []peer.ID 30 | for _, a := range ai { 31 | pis = append(pis, a.ID) 32 | } 33 | return pis 34 | } 35 | -------------------------------------------------------------------------------- /net/address_test.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | import ( 4 | "testing" 5 | 6 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestPeerAddrsToPeerInfosSuccess(t *testing.T) { 11 | tf.UnitTest(t) 12 | 13 | addrs := []string{ 14 | "/ip4/127.0.0.1/ipfs/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", 15 | "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", 16 | } 17 | pis, err := PeerAddrsToAddrInfo(addrs) 18 | assert.NoError(t, err) 19 | assert.Equal(t, "QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", pis[0].ID.Pretty()) 20 | assert.Equal(t, "QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", pis[1].ID.Pretty()) 21 | } 22 | 23 | func TestPeerAddrsToPeerInfosFailure(t *testing.T) { 24 | tf.UnitTest(t) 25 | 26 | addrs := []string{ 27 | "/ipv4/no/such/address/ipfs/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", 28 | } 29 | _, err := PeerAddrsToAddrInfo(addrs) 30 | assert.Error(t, err) 31 | } 32 | -------------------------------------------------------------------------------- /net/pinger.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | "github.com/libp2p/go-libp2p-core/host" 8 | "github.com/libp2p/go-libp2p-core/peer" 9 | "github.com/libp2p/go-libp2p/p2p/protocol/ping" 10 | ) 11 | 12 | // ErrPingSelf is returned if the pinger is instructed to ping itself. 13 | var ErrPingSelf = errors.New("cannot ping self") 14 | 15 | // Pinger wraps a libp2p ping service. It exists to serve more helpful 16 | // error messages in the case a node is pinging itself. 17 | type Pinger struct { 18 | *ping.PingService 19 | self host.Host 20 | } 21 | 22 | // NewPinger creates a filecoin pinger provided with a pingService and a PID. 23 | func NewPinger(h host.Host, p *ping.PingService) *Pinger { 24 | return &Pinger{ 25 | PingService: p, 26 | self: h, 27 | } 28 | } 29 | 30 | // Ping connects to other nodes on the network to test connections. The 31 | // Pinger will error if the caller Pings the Pinger's self id. 32 | func (p *Pinger) Ping(ctx context.Context, pid peer.ID) (<-chan ping.Result, error) { 33 | if pid == p.self.ID() { 34 | return nil, ErrPingSelf 35 | } 36 | return p.PingService.Ping(ctx, pid), nil 37 | } 38 | -------------------------------------------------------------------------------- /net/protocols.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/libp2p/go-libp2p-core/protocol" 7 | ) 8 | 9 | // FilecoinDHT is creates a protocol for the filecoin DHT. 10 | func FilecoinDHT(network string) protocol.ID { 11 | return protocol.ID(fmt.Sprintf("/fil/kad/%s", network)) 12 | } 13 | -------------------------------------------------------------------------------- /net/pubsub/publisher.go: -------------------------------------------------------------------------------- 1 | package pubsub 2 | 3 | import "github.com/libp2p/go-libp2p-pubsub" 4 | 5 | // Publisher publishes to pubsub topics 6 | type Publisher struct { 7 | pubsub *pubsub.PubSub 8 | } 9 | 10 | // NewPublisher builds a new publisher 11 | func NewPublisher(sub *pubsub.PubSub) *Publisher { 12 | return &Publisher{pubsub: sub} 13 | } 14 | 15 | // Publish publishes to a pubsub topic 16 | func (s *Publisher) Publish(topic string, data []byte) error { 17 | return s.pubsub.Publish(topic, data) 18 | } 19 | -------------------------------------------------------------------------------- /net/pubsub/subscriber.go: -------------------------------------------------------------------------------- 1 | package pubsub 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/libp2p/go-libp2p-core/peer" 7 | libp2p "github.com/libp2p/go-libp2p-pubsub" 8 | ) 9 | 10 | // Subscriber subscribes to pubsub topics 11 | type Subscriber struct { 12 | pubsub *libp2p.PubSub 13 | } 14 | 15 | // Message defines the common interface for go-filecoin message consumers. 16 | // It's a subset of the go-libp2p-pubsub/pubsub.go Message type. 17 | type Message interface { 18 | GetFrom() peer.ID 19 | GetData() []byte 20 | } 21 | 22 | // Subscription is a handle to a pubsub subscription. 23 | // This matches part of the interface to a libp2p.pubsub.Subscription. 24 | type Subscription interface { 25 | // Topic returns this subscription's topic name 26 | Topic() string 27 | // Next returns the next message from this subscription 28 | Next(ctx context.Context) (Message, error) 29 | // Cancel cancels this subscription 30 | Cancel() 31 | } 32 | 33 | // NewSubscriber builds a new subscriber 34 | func NewSubscriber(sub *libp2p.PubSub) *Subscriber { 35 | return &Subscriber{pubsub: sub} 36 | } 37 | 38 | // Subscribe subscribes to a pubsub topic 39 | func (s *Subscriber) Subscribe(topic string) (Subscription, error) { 40 | sub, e := s.pubsub.Subscribe(topic) 41 | return &subscriptionWrapper{sub}, e 42 | } 43 | 44 | // subscriptionWrapper extends a pubsub.Subscription in order to wrap the Message type. 45 | type subscriptionWrapper struct { 46 | *libp2p.Subscription 47 | } 48 | 49 | // Next wraps pubsub.Subscription.Next, implicitly adapting *pubsub.Message to the Message interface. 50 | func (w subscriptionWrapper) Next(ctx context.Context) (Message, error) { 51 | return w.Subscription.Next(ctx) 52 | } 53 | -------------------------------------------------------------------------------- /net/topics.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | import "fmt" 4 | 5 | // BlockTopic returns the network pubsub topic identifier on which new blocks are announced. 6 | func BlockTopic(networkName string) string { 7 | return fmt.Sprintf("/fil/blocks/%s", networkName) 8 | } 9 | 10 | // MessageTopic returns the network pubsub topic identifier on which new messages are announced. 11 | func MessageTopic(networkName string) string { 12 | return fmt.Sprintf("/fil/msgs/%s", networkName) 13 | } 14 | -------------------------------------------------------------------------------- /node/block_mining_submodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import ( 4 | "context" 5 | "sync" 6 | 7 | "github.com/filecoin-project/go-filecoin/mining" 8 | "github.com/filecoin-project/go-filecoin/protocol/block" 9 | ) 10 | 11 | // BlockMiningSubmodule enhances the `Node` with block mining capabilities. 12 | type BlockMiningSubmodule struct { 13 | BlockMiningAPI *block.MiningAPI 14 | 15 | // Mining stuff. 16 | AddNewlyMinedBlock newBlockFunc 17 | // cancelMining cancels the context for block production and sector commitments. 18 | cancelMining context.CancelFunc 19 | MiningWorker mining.Worker 20 | MiningScheduler mining.Scheduler 21 | mining struct { 22 | sync.Mutex 23 | isMining bool 24 | } 25 | miningDoneWg *sync.WaitGroup 26 | } 27 | -------------------------------------------------------------------------------- /node/blockservice_submoodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import ( 4 | bserv "github.com/ipfs/go-blockservice" 5 | ) 6 | 7 | // BlockserviceSubmodule enhances the `Node` with networked key/value fetching capabilities. 8 | // 9 | // TODO: split chain data from piece data (issue: https://github.com/filecoin-project/go-filecoin/issues/3481) 10 | // Note: at present: 11 | // - `BlockService` is shared by chain/graphsync and piece/bitswap data 12 | type BlockserviceSubmodule struct { 13 | // Blockservice is a higher level interface for fetching data 14 | blockservice bserv.BlockService 15 | } 16 | -------------------------------------------------------------------------------- /node/blockstore_submodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import ( 4 | "github.com/ipfs/go-hamt-ipld" 5 | bstore "github.com/ipfs/go-ipfs-blockstore" 6 | ) 7 | 8 | // BlockstoreSubmodule enhances the `Node` with local key/value storing capabilities. 9 | // 10 | // TODO: split chain data from piece data (issue: https://github.com/filecoin-project/go-filecoin/issues/3481) 11 | // Note: at present: 12 | // - `Blockstore` is shared by chain/graphsync and piece/bitswap data 13 | // - `cborStore` is used for chain state and shared with piece data exchange for deals at the moment. 14 | type BlockstoreSubmodule struct { 15 | // Blockstore is the un-networked blocks interface 16 | Blockstore bstore.Blockstore 17 | 18 | // cborStore is a wrapper for a `hamt.CborIpldStore` that works on the local IPLD-Cbor objects stored in `Blockstore`. 19 | cborStore *hamt.CborIpldStore 20 | } 21 | -------------------------------------------------------------------------------- /node/chain_submodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/chain" 7 | "github.com/filecoin-project/go-filecoin/consensus" 8 | "github.com/filecoin-project/go-filecoin/net" 9 | "github.com/filecoin-project/go-filecoin/net/pubsub" 10 | "github.com/filecoin-project/go-filecoin/plumbing/cst" 11 | "github.com/filecoin-project/go-filecoin/util/moresync" 12 | ) 13 | 14 | // ChainSubmodule enhances the `Node` with chain capabilities. 15 | type ChainSubmodule struct { 16 | BlockSub pubsub.Subscription 17 | Consensus consensus.Protocol 18 | ChainSelector nodeChainSelector 19 | ChainReader nodeChainReader 20 | MessageStore *chain.MessageStore 21 | Syncer nodeChainSyncer 22 | ActorState *consensus.ActorStateStore 23 | 24 | // HeavyTipSetCh is a subscription to the heaviest tipset topic on the chain. 25 | // https://github.com/filecoin-project/go-filecoin/issues/2309 26 | HeaviestTipSetCh chan interface{} 27 | // cancelChainSync cancels the context for chain sync subscriptions and handlers. 28 | cancelChainSync context.CancelFunc 29 | // ChainSynced is a latch that releases when a nodes chain reaches a caught-up state. 30 | // It serves as a barrier to be released when the initial chain sync has completed. 31 | // Services which depend on a more-or-less synced chain can wait for this before starting up. 32 | ChainSynced *moresync.Latch 33 | // Fetcher is the interface for fetching data from nodes. 34 | Fetcher net.Fetcher 35 | State *cst.ChainStateReadWriter 36 | 37 | validator consensus.BlockValidator 38 | processor *consensus.DefaultProcessor 39 | } 40 | -------------------------------------------------------------------------------- /node/config.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import ( 4 | libp2p "github.com/libp2p/go-libp2p" 5 | ci "github.com/libp2p/go-libp2p-core/crypto" 6 | errors "github.com/pkg/errors" 7 | 8 | "github.com/filecoin-project/go-filecoin/repo" 9 | ) 10 | 11 | // OptionsFromRepo takes a repo and returns options that configure a node 12 | // to use the given repo. 13 | func OptionsFromRepo(r repo.Repo) ([]BuilderOpt, error) { 14 | sk, err := privKeyFromKeystore(r) 15 | if err != nil { 16 | return nil, err 17 | } 18 | 19 | cfg := r.Config() 20 | cfgopts := []BuilderOpt{ 21 | // Libp2pOptions can only be called once, so add all options here. 22 | Libp2pOptions( 23 | libp2p.ListenAddrStrings(cfg.Swarm.Address), 24 | libp2p.Identity(sk), 25 | ), 26 | } 27 | 28 | dsopt := func(c *Builder) error { 29 | c.Repo = r 30 | return nil 31 | } 32 | 33 | return append(cfgopts, dsopt), nil 34 | } 35 | 36 | func privKeyFromKeystore(r repo.Repo) (ci.PrivKey, error) { 37 | sk, err := r.Keystore().Get("self") 38 | if err != nil { 39 | return nil, errors.Wrap(err, "failed to get key from keystore") 40 | } 41 | 42 | return sk, nil 43 | } 44 | -------------------------------------------------------------------------------- /node/fault_slasher_submodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | // FaultSlasherSubmodule enhances the `Node` with storage slashing capabilities. 4 | type FaultSlasherSubmodule struct { 5 | StorageFaultSlasher storageFaultSlasher 6 | } 7 | -------------------------------------------------------------------------------- /node/hello_protocol_submodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import "github.com/filecoin-project/go-filecoin/protocol/hello" 4 | 5 | // HelloProtocolSubmodule enhances the `Node` with "Hello" protocol capabilities. 6 | type HelloProtocolSubmodule struct { 7 | HelloSvc *hello.Handler 8 | } 9 | -------------------------------------------------------------------------------- /node/message.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/net/pubsub" 7 | "github.com/filecoin-project/go-filecoin/types" 8 | ) 9 | 10 | func (node *Node) processMessage(ctx context.Context, pubSubMsg pubsub.Message) (err error) { 11 | ctx = log.Start(ctx, "Node.processMessage") 12 | defer func() { 13 | log.FinishWithErr(ctx, err) 14 | }() 15 | 16 | unmarshaled := &types.SignedMessage{} 17 | if err := unmarshaled.Unmarshal(pubSubMsg.GetData()); err != nil { 18 | return err 19 | } 20 | log.SetTag(ctx, "message", unmarshaled) 21 | 22 | log.Debugf("Received new message %s from peer %s", unmarshaled, pubSubMsg.GetFrom()) 23 | 24 | _, err = node.Messaging.Inbox.Add(ctx, unmarshaled) 25 | return err 26 | } 27 | -------------------------------------------------------------------------------- /node/messaging_submodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import ( 4 | "github.com/filecoin-project/go-filecoin/message" 5 | "github.com/filecoin-project/go-filecoin/net/pubsub" 6 | ) 7 | 8 | // MessagingSubmodule enhances the `Node` with internal messaging capabilities. 9 | type MessagingSubmodule struct { 10 | // Incoming messages for block mining. 11 | Inbox *message.Inbox 12 | 13 | // Messages sent and not yet mined. 14 | Outbox *message.Outbox 15 | 16 | // Network Fields 17 | MessageSub pubsub.Subscription 18 | 19 | msgPool *message.Pool 20 | } 21 | -------------------------------------------------------------------------------- /node/network_submodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import ( 4 | "github.com/filecoin-project/go-filecoin/net" 5 | exchange "github.com/ipfs/go-ipfs-exchange-interface" 6 | "github.com/libp2p/go-libp2p-core/host" 7 | "github.com/libp2p/go-libp2p-core/routing" 8 | libp2pps "github.com/libp2p/go-libp2p-pubsub" 9 | ) 10 | 11 | // NetworkSubmodule enhances the `Node` with networking capabilities. 12 | type NetworkSubmodule struct { 13 | NetworkName string 14 | 15 | host host.Host 16 | 17 | // TODO: do we need a second host? (see: https://github.com/filecoin-project/go-filecoin/issues/3477) 18 | PeerHost host.Host 19 | 20 | Bootstrapper *net.Bootstrapper 21 | 22 | // PeerTracker maintains a list of peers good for fetching. 23 | PeerTracker *net.PeerTracker 24 | 25 | // Router is a router from IPFS 26 | Router routing.Routing 27 | 28 | fsub *libp2pps.PubSub 29 | 30 | // TODO: split chain bitswap from storage bitswap (issue: ???) 31 | bitswap exchange.Interface 32 | 33 | Network *net.Network 34 | } 35 | -------------------------------------------------------------------------------- /node/retrieval_protocol_submodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import "github.com/filecoin-project/go-filecoin/protocol/retrieval" 4 | 5 | // RetrievalProtocolSubmodule enhances the `Node` with "Retrieval" protocol capabilities. 6 | type RetrievalProtocolSubmodule struct { 7 | RetrievalAPI *retrieval.API 8 | 9 | // Retrieval Interfaces 10 | RetrievalMiner *retrieval.Miner 11 | } 12 | -------------------------------------------------------------------------------- /node/sector_builder_submodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import "github.com/filecoin-project/go-filecoin/proofs/sectorbuilder" 4 | 5 | // SectorBuilderSubmodule enhances the `Node` with sector storage capabilities. 6 | type SectorBuilderSubmodule struct { 7 | // SectorBuilder is used by the miner to fill and seal sectors. 8 | sectorBuilder sectorbuilder.SectorBuilder 9 | } 10 | -------------------------------------------------------------------------------- /node/storage_networking_submodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import exchange "github.com/ipfs/go-ipfs-exchange-interface" 4 | 5 | // StorageNetworkingSubmodule enhances the `Node` with data transfer capabilities. 6 | type StorageNetworkingSubmodule struct { 7 | // Exchange is the interface for fetching data from other nodes. 8 | Exchange exchange.Interface 9 | } 10 | -------------------------------------------------------------------------------- /node/storage_protocol_submodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import "github.com/filecoin-project/go-filecoin/protocol/storage" 4 | 5 | // StorageProtocolSubmodule enhances the `Node` with "Storage" protocol capabilities. 6 | type StorageProtocolSubmodule struct { 7 | StorageAPI *storage.API 8 | 9 | // Storage Market Interfaces 10 | StorageMiner *storage.Miner 11 | } 12 | -------------------------------------------------------------------------------- /node/wallet_submodule.go: -------------------------------------------------------------------------------- 1 | package node 2 | 3 | import "github.com/filecoin-project/go-filecoin/wallet" 4 | 5 | // WalletSubmodule enhances the `Node` with a "Wallet" and FIL transfer capabilities. 6 | type WalletSubmodule struct { 7 | Wallet *wallet.Wallet 8 | } 9 | -------------------------------------------------------------------------------- /plumbing/cfg/config.go: -------------------------------------------------------------------------------- 1 | package cfg 2 | 3 | import ( 4 | "github.com/filecoin-project/go-filecoin/repo" 5 | "sync" 6 | ) 7 | 8 | // Config is plumbing implementation for setting and retrieving values from local config. 9 | type Config struct { 10 | repo repo.Repo 11 | lock sync.Mutex 12 | } 13 | 14 | // NewConfig returns a new Config. 15 | func NewConfig(repo repo.Repo) *Config { 16 | return &Config{repo: repo} 17 | } 18 | 19 | // Set sets a value in config 20 | func (s *Config) Set(dottedKey string, jsonString string) error { 21 | s.lock.Lock() 22 | defer s.lock.Unlock() 23 | 24 | cfg := s.repo.Config() 25 | if err := cfg.Set(dottedKey, jsonString); err != nil { 26 | return err 27 | } 28 | 29 | return s.repo.ReplaceConfig(cfg) 30 | } 31 | 32 | // Get gets a value from config 33 | func (s *Config) Get(dottedKey string) (interface{}, error) { 34 | return s.repo.Config().Get(dottedKey) 35 | } 36 | -------------------------------------------------------------------------------- /plumbing/cst/chain_sync.go: -------------------------------------------------------------------------------- 1 | package cst 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/chain" 7 | "github.com/filecoin-project/go-filecoin/types" 8 | ) 9 | 10 | type chainSync interface { 11 | HandleNewTipSet(context.Context, *types.ChainInfo, bool) error 12 | Status() chain.Status 13 | } 14 | 15 | // ChainSyncProvider provides access to chain sync operations and their status. 16 | type ChainSyncProvider struct { 17 | sync chainSync 18 | } 19 | 20 | // NewChainSyncProvider returns a new ChainSyncProvider. 21 | func NewChainSyncProvider(chainSyncer chainSync) *ChainSyncProvider { 22 | return &ChainSyncProvider{ 23 | sync: chainSyncer, 24 | } 25 | } 26 | 27 | // Status returns the chains current status, this includes whether or not the syncer is currently 28 | // running, the chain being synced, and the time it started processing said chain. 29 | func (chs *ChainSyncProvider) Status() chain.Status { 30 | return chs.sync.Status() 31 | } 32 | 33 | // HandleNewTipSet extends the Syncer's chain store with the given tipset if they 34 | // represent a valid extension. It limits the length of new chains it will 35 | // attempt to validate and caches invalid blocks it has encountered to 36 | // help prevent DOS. 37 | func (chs *ChainSyncProvider) HandleNewTipSet(ctx context.Context, ci *types.ChainInfo, trusted bool) error { 38 | return chs.sync.HandleNewTipSet(ctx, ci, trusted) 39 | } 40 | -------------------------------------------------------------------------------- /plumbing/strgdls/store.go: -------------------------------------------------------------------------------- 1 | package strgdls 2 | 3 | import ( 4 | "github.com/ipfs/go-datastore" 5 | "github.com/ipfs/go-datastore/query" 6 | cbor "github.com/ipfs/go-ipld-cbor" 7 | "github.com/pkg/errors" 8 | 9 | "github.com/filecoin-project/go-filecoin/protocol/storage/storagedeal" 10 | "github.com/filecoin-project/go-filecoin/repo" 11 | ) 12 | 13 | // Store is plumbing implementation querying deals 14 | type Store struct { 15 | dealsDs repo.Datastore 16 | } 17 | 18 | // StorageDealPrefix is the datastore prefix for storage deals 19 | const StorageDealPrefix = "storagedeals" 20 | 21 | // New returns a new Store. 22 | func New(dealsDatastore repo.Datastore) *Store { 23 | return &Store{dealsDs: dealsDatastore} 24 | } 25 | 26 | // Iterator returns an iterator with deals matching the given query 27 | func (store *Store) Iterator() (*query.Results, error) { 28 | results, err := store.dealsDs.Query(query.Query{Prefix: "/" + StorageDealPrefix}) 29 | if err != nil { 30 | return nil, errors.Wrap(err, "failed to query deals from datastore") 31 | } 32 | return &results, nil 33 | } 34 | 35 | // Put puts the deal into the datastore 36 | func (store *Store) Put(storageDeal *storagedeal.Deal) error { 37 | proposalCid := storageDeal.Response.ProposalCid 38 | datum, err := cbor.DumpObject(storageDeal) 39 | if err != nil { 40 | return errors.Wrap(err, "could not marshal storageDeal") 41 | } 42 | 43 | key := datastore.KeyWithNamespaces([]string{StorageDealPrefix, proposalCid.String()}) 44 | err = store.dealsDs.Put(key, datum) 45 | if err != nil { 46 | return errors.Wrap(err, "could not save storage deal to disk") 47 | } 48 | 49 | return nil 50 | } 51 | -------------------------------------------------------------------------------- /porcelain/chain.go: -------------------------------------------------------------------------------- 1 | package porcelain 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/ipfs/go-cid" 7 | 8 | "github.com/filecoin-project/go-filecoin/types" 9 | ) 10 | 11 | type chainHeadPlumbing interface { 12 | ChainHeadKey() types.TipSetKey 13 | ChainTipSet(key types.TipSetKey) (types.TipSet, error) 14 | } 15 | 16 | // ChainHead gets the current head tipset from plumbing. 17 | func ChainHead(plumbing chainHeadPlumbing) (types.TipSet, error) { 18 | return plumbing.ChainTipSet(plumbing.ChainHeadKey()) 19 | } 20 | 21 | type fullBlockPlumbing interface { 22 | ChainGetBlock(context.Context, cid.Cid) (*types.Block, error) 23 | ChainGetMessages(context.Context, cid.Cid) ([]*types.SignedMessage, error) 24 | ChainGetReceipts(context.Context, cid.Cid) ([]*types.MessageReceipt, error) 25 | } 26 | 27 | // GetFullBlock returns a full block: header, messages, receipts. 28 | func GetFullBlock(ctx context.Context, plumbing fullBlockPlumbing, id cid.Cid) (*types.FullBlock, error) { 29 | var out types.FullBlock 30 | var err error 31 | 32 | out.Header, err = plumbing.ChainGetBlock(ctx, id) 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | out.Messages, err = plumbing.ChainGetMessages(ctx, out.Header.Messages) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | out.Receipts, err = plumbing.ChainGetReceipts(ctx, out.Header.MessageReceipts) 43 | if err != nil { 44 | return nil, err 45 | } 46 | 47 | return &out, nil 48 | } 49 | -------------------------------------------------------------------------------- /porcelain/mpool.go: -------------------------------------------------------------------------------- 1 | package porcelain 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/filecoin-project/go-filecoin/types" 8 | ) 9 | 10 | // The subset of plumbing used by MessagePoolWait 11 | type mpwPlumbing interface { 12 | MessagePoolPending() []*types.SignedMessage 13 | } 14 | 15 | // MessagePoolWait waits until the message pool contains at least messageCount unmined messages. 16 | func MessagePoolWait(ctx context.Context, plumbing mpwPlumbing, messageCount uint) ([]*types.SignedMessage, error) { 17 | pending := plumbing.MessagePoolPending() 18 | for len(pending) < int(messageCount) { 19 | // Poll pending again after subscribing in case a message arrived since. 20 | pending = plumbing.MessagePoolPending() 21 | time.Sleep(200 * time.Millisecond) 22 | } 23 | 24 | return pending, nil 25 | } 26 | -------------------------------------------------------------------------------- /porcelain/network.go: -------------------------------------------------------------------------------- 1 | package porcelain 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/libp2p/go-libp2p-core/peer" 9 | "github.com/libp2p/go-libp2p/p2p/protocol/ping" 10 | "github.com/pkg/errors" 11 | ) 12 | 13 | type netPlumbing interface { 14 | NetworkPing(ctx context.Context, pid peer.ID) (<-chan ping.Result, error) 15 | } 16 | 17 | // PingMinerWithTimeout pings a storage or retrieval miner, waiting the given 18 | // timeout and returning descriptive errors. 19 | func PingMinerWithTimeout(ctx context.Context, minerPID peer.ID, timeout time.Duration, plumbing netPlumbing) error { 20 | ctx, cancel := context.WithTimeout(ctx, timeout) 21 | defer cancel() 22 | 23 | res, err := netPlumbing.NetworkPing(plumbing, ctx, minerPID) 24 | if err != nil { 25 | return err 26 | } 27 | 28 | select { 29 | case _, ok := <-res: 30 | if !ok { 31 | return errors.New("couldn't establish connection to miner: ping channel closed") 32 | } 33 | return nil 34 | case <-ctx.Done(): 35 | return fmt.Errorf("couldn't establish connection to miner: %s, timed out after %s", ctx.Err(), timeout.String()) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /proofs/piece_commitment.go: -------------------------------------------------------------------------------- 1 | package proofs 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "io/ioutil" 7 | "os" 8 | 9 | "github.com/filecoin-project/go-filecoin/types" 10 | "github.com/filecoin-project/go-sectorbuilder" 11 | ) 12 | 13 | // GeneratePieceCommitmentRequest represents a request to generate a piece 14 | // commitment (merkle root) of the data in a provided reader. 15 | type GeneratePieceCommitmentRequest struct { 16 | PieceReader io.Reader 17 | PieceSize *types.BytesAmount 18 | } 19 | 20 | // GeneratePieceCommitmentResponse represents the commitment bytes 21 | type GeneratePieceCommitmentResponse struct { 22 | CommP types.CommP 23 | } 24 | 25 | // GeneratePieceCommitment produces a piece commitment for the provided data 26 | // stored at a given piece path. 27 | func GeneratePieceCommitment(req GeneratePieceCommitmentRequest) (res GeneratePieceCommitmentResponse, retErr error) { 28 | file, err := ioutil.TempFile("", "") 29 | if err != nil { 30 | retErr = err 31 | return 32 | } 33 | 34 | defer func() { 35 | err := os.Remove(file.Name()) 36 | if err != nil && retErr == nil { 37 | retErr = err 38 | } 39 | }() 40 | 41 | n, err := io.Copy(file, req.PieceReader) 42 | if err != nil { 43 | retErr = err 44 | return 45 | } 46 | 47 | if !types.NewBytesAmount(uint64(n)).Equal(req.PieceSize) { 48 | retErr = fmt.Errorf("was unable to write all piece bytes to temp file (wrote %dB, pieceSize %dB)", n, req.PieceSize.Uint64()) 49 | return 50 | } 51 | 52 | commP, err := go_sectorbuilder.GeneratePieceCommitment(file.Name(), req.PieceSize.Uint64()) 53 | if err != nil { 54 | retErr = err 55 | return 56 | } 57 | 58 | res = GeneratePieceCommitmentResponse{ 59 | CommP: commP, 60 | } 61 | 62 | return 63 | } 64 | -------------------------------------------------------------------------------- /proofs/sectorbuilder/bytesink/interface.go: -------------------------------------------------------------------------------- 1 | package bytesink 2 | 3 | import "io" 4 | 5 | // ByteSink represents a location to which bytes can be written. The ByteSink 6 | // should be closed after all bytes have been written. 7 | type ByteSink interface { 8 | io.Writer 9 | io.Closer 10 | Open() error 11 | ID() string 12 | } 13 | -------------------------------------------------------------------------------- /proofs/sectorbuilder/errors.go: -------------------------------------------------------------------------------- 1 | package sectorbuilder 2 | 3 | import ( 4 | "fmt" 5 | "github.com/pkg/errors" 6 | ) 7 | 8 | // ErrPieceTooLarge is an error indicating that a piece cannot be larger than the sector into which it is written. 9 | var ErrPieceTooLarge = errors.New("piece too large for sector") 10 | 11 | // ErrCouldNotRevertUnsealedSector is an error indicating that a revert of an unsealed sector failed due to 12 | // rollbackErr. This revert was originally triggered by the rollbackCause error 13 | type ErrCouldNotRevertUnsealedSector struct { 14 | rollbackErr error 15 | rollbackCause error 16 | } 17 | 18 | // NewErrCouldNotRevertUnsealedSector produces an ErrCouldNotRevertUnsealedSector. 19 | func NewErrCouldNotRevertUnsealedSector(rollbackErr error, rollbackCause error) error { 20 | return &ErrCouldNotRevertUnsealedSector{ 21 | rollbackErr: rollbackErr, 22 | rollbackCause: rollbackCause, 23 | } 24 | } 25 | 26 | func (e *ErrCouldNotRevertUnsealedSector) Error() string { 27 | return fmt.Sprintf("rollback error: %s, rollback cause: %s", e.rollbackErr.Error(), e.rollbackCause.Error()) 28 | } 29 | -------------------------------------------------------------------------------- /proofs/sectorbuilder/utils.go: -------------------------------------------------------------------------------- 1 | package sectorbuilder 2 | 3 | import ( 4 | "bytes" 5 | 6 | "github.com/filecoin-project/go-filecoin/address" 7 | ) 8 | 9 | // AddressToProverID creates a prover id by padding an address hash to 31 bytes 10 | func AddressToProverID(addr address.Address) [31]byte { 11 | // this code will no longer WAE when ID's or BLS pub keys are added 12 | // as they will break the assumption of addresses all being the same length 13 | if addr.Protocol() != address.Actor && addr.Protocol() != address.SECP256K1 { 14 | panic("cannot create prover hash from new address protocol") 15 | } 16 | hash := addr.Payload() 17 | 18 | dlen := 31 // desired length 19 | hlen := len(hash) // hash length 20 | padl := dlen - hlen // padding length 21 | 22 | var prid [31]byte 23 | 24 | // will copy dlen bytes from hash 25 | copy(prid[:], hash) 26 | 27 | if padl > 0 { 28 | copy(prid[hlen:], bytes.Repeat([]byte{0}, padl)) 29 | } 30 | 31 | return prid 32 | } 33 | -------------------------------------------------------------------------------- /proofs/sectorbuilder/utils_test.go: -------------------------------------------------------------------------------- 1 | package sectorbuilder 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/filecoin-project/go-filecoin/address" 7 | 8 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func TestSectorBuilderUtils(t *testing.T) { 13 | tf.UnitTest(t) 14 | 15 | t.Run("prover id creation", func(t *testing.T) { 16 | addr, err := address.NewActorAddress([]byte("satoshi")) 17 | require.NoError(t, err) 18 | 19 | id := AddressToProverID(addr) 20 | 21 | require.Equal(t, 31, len(id)) 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /proofs/verification/rustverifier.go: -------------------------------------------------------------------------------- 1 | package verification 2 | 3 | import ( 4 | "github.com/filecoin-project/go-sectorbuilder" 5 | ) 6 | 7 | // RustVerifier provides proof-verification methods. 8 | type RustVerifier struct{} 9 | 10 | var _ Verifier = &RustVerifier{} 11 | 12 | // VerifySeal returns nil if the Seal operation from which its inputs were 13 | // derived was valid, and an error if not. 14 | func (rp *RustVerifier) VerifySeal(req VerifySealRequest) (VerifySealResponse, error) { 15 | isValid, err := go_sectorbuilder.VerifySeal(req.SectorSize.Uint64(), req.CommR, req.CommD, req.CommRStar, req.ProverID, req.SectorID, req.Proof) 16 | if err != nil { 17 | return VerifySealResponse{}, err 18 | } 19 | 20 | return VerifySealResponse{ 21 | IsValid: isValid, 22 | }, nil 23 | } 24 | 25 | // VerifyPoSt verifies that a proof-of-spacetime is valid. 26 | func (rp *RustVerifier) VerifyPoSt(req VerifyPoStRequest) (VerifyPoStResponse, error) { 27 | isValid, err := go_sectorbuilder.VerifyPoSt(req.SectorSize.Uint64(), req.SortedSectorInfo, req.ChallengeSeed, req.Proof, req.Faults) 28 | if err != nil { 29 | return VerifyPoStResponse{}, err 30 | } 31 | 32 | return VerifyPoStResponse{ 33 | IsValid: isValid, 34 | }, nil 35 | } 36 | 37 | // VerifyPieceInclusionProof returns true if the piece inclusion proof is valid 38 | // with the given arguments. 39 | func (rp *RustVerifier) VerifyPieceInclusionProof(req VerifyPieceInclusionProofRequest) (VerifyPieceInclusionProofResponse, error) { 40 | isValid, err := go_sectorbuilder.VerifyPieceInclusionProof(req.SectorSize.Uint64(), req.PieceSize.Uint64(), req.CommP, req.CommD, req.PieceInclusionProof) 41 | if err != nil { 42 | return VerifyPieceInclusionProofResponse{}, err 43 | } 44 | 45 | return VerifyPieceInclusionProofResponse{ 46 | IsValid: isValid, 47 | }, nil 48 | } 49 | -------------------------------------------------------------------------------- /proofs/verification/testing.go: -------------------------------------------------------------------------------- 1 | package verification 2 | 3 | // FakeVerifier is a simple mock Verifier for testing. 4 | type FakeVerifier struct { 5 | VerifyPoStValid bool 6 | VerifyPoStError error 7 | VerifyPieceInclusionProofValid bool 8 | VerifyPieceInclusionProofError error 9 | VerifySealValid bool 10 | VerifySealError error 11 | 12 | // these requests will be captured by code that calls VerifySeal or VerifyPoSt or VerifyPieceInclusionProof 13 | LastReceivedVerifySealRequest *VerifySealRequest 14 | LastReceivedVerifyPoStRequest *VerifyPoStRequest 15 | LastReceivedVerifyPieceInclusionProofRequest *VerifyPieceInclusionProofRequest 16 | } 17 | 18 | var _ Verifier = (*FakeVerifier)(nil) 19 | 20 | // VerifyPoSt fakes out PoSt proof verification, skipping an FFI call to 21 | // generate_post. 22 | func (fp *FakeVerifier) VerifyPoSt(req VerifyPoStRequest) (VerifyPoStResponse, error) { 23 | fp.LastReceivedVerifyPoStRequest = &req 24 | return VerifyPoStResponse{IsValid: fp.VerifyPoStValid}, fp.VerifyPoStError 25 | } 26 | 27 | // VerifySeal fakes out seal (PoRep) proof verification, skipping an FFI call to 28 | // verify_seal. 29 | func (fp *FakeVerifier) VerifySeal(req VerifySealRequest) (VerifySealResponse, error) { 30 | fp.LastReceivedVerifySealRequest = &req 31 | return VerifySealResponse{IsValid: fp.VerifySealValid}, fp.VerifySealError 32 | } 33 | 34 | // VerifyPieceInclusionProof fakes out PIP verification, skipping an FFI call to 35 | // verify_piece_inclusion_proof. 36 | func (fp *FakeVerifier) VerifyPieceInclusionProof(req VerifyPieceInclusionProofRequest) (VerifyPieceInclusionProofResponse, error) { 37 | fp.LastReceivedVerifyPieceInclusionProofRequest = &req 38 | return VerifyPieceInclusionProofResponse{IsValid: fp.VerifyPieceInclusionProofValid}, fp.VerifyPieceInclusionProofError 39 | } 40 | -------------------------------------------------------------------------------- /protocol/retrieval/api.go: -------------------------------------------------------------------------------- 1 | package retrieval 2 | 3 | import ( 4 | "context" 5 | "io" 6 | 7 | "github.com/ipfs/go-cid" 8 | "github.com/libp2p/go-libp2p-core/peer" 9 | 10 | "github.com/filecoin-project/go-filecoin/address" 11 | ) 12 | 13 | // API here is the API for a retrieval client. 14 | type API struct { 15 | rc *Client 16 | } 17 | 18 | // NewAPI creates a new API for a retrieval client. 19 | func NewAPI(rc *Client) API { 20 | return API{rc: rc} 21 | } 22 | 23 | // RetrievePiece retrieves bytes referenced by CID pieceCID 24 | func (a *API) RetrievePiece(ctx context.Context, pieceCID cid.Cid, mpid peer.ID, minerAddr address.Address) (io.ReadCloser, error) { 25 | return a.rc.RetrievePiece(ctx, mpid, pieceCID) 26 | } 27 | -------------------------------------------------------------------------------- /protocol/retrieval/doc.go: -------------------------------------------------------------------------------- 1 | // Package retrieval implements a very simple retrieval protocol that works on high level like this: 2 | // 3 | // 1. CLIENT opens /fil/retrieval/free/0.0.0 stream to MINER 4 | // 2. CLIENT sends MINER a RetrievePieceRequest 5 | // 3. MINER sends CLIENT a RetrievePieceResponse with Status set to Success if it has PieceRef in a sealed sector 6 | // 4. MINER sends CLIENT RetrievePieceChunks until all data associated with PieceRef has been sent 7 | // 5. CLIENT reads RetrievePieceChunk from stream until EOF and then closes stream 8 | package retrieval 9 | -------------------------------------------------------------------------------- /protocol/retrieval/types.go: -------------------------------------------------------------------------------- 1 | package retrieval 2 | 3 | import ( 4 | "github.com/ipfs/go-cid" 5 | cbor "github.com/ipfs/go-ipld-cbor" 6 | ) 7 | 8 | func init() { 9 | cbor.RegisterCborType(RetrievePieceRequest{}) 10 | cbor.RegisterCborType(RetrievePieceResponse{}) 11 | cbor.RegisterCborType(RetrievePieceChunk{}) 12 | } 13 | 14 | // RetrievePieceStatus communicates a successful (or failed) piece retrieval 15 | type RetrievePieceStatus int 16 | 17 | const ( 18 | // Unset is the default status 19 | Unset = RetrievePieceStatus(iota) 20 | 21 | // Failure indicates that the piece could not be retrieved from the miner 22 | Failure 23 | 24 | // Success means that the piece could be retrieved from the miner 25 | Success 26 | ) 27 | 28 | // RetrievePieceRequest represents a retrieval miner's request for content. 29 | type RetrievePieceRequest struct { 30 | PieceRef cid.Cid 31 | } 32 | 33 | // RetrievePieceResponse contains the requested content. 34 | type RetrievePieceResponse struct { 35 | Status RetrievePieceStatus 36 | ErrorMessage string 37 | } 38 | 39 | // RetrievePieceChunk is a subset of bytes for a piece being retrieved. 40 | type RetrievePieceChunk struct { 41 | Data []byte 42 | } 43 | -------------------------------------------------------------------------------- /protocol/storage/api.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/ipfs/go-cid" 7 | 8 | "github.com/filecoin-project/go-filecoin/address" 9 | "github.com/filecoin-project/go-filecoin/protocol/storage/storagedeal" 10 | "github.com/filecoin-project/go-filecoin/types" 11 | ) 12 | 13 | // API here is the API for a storage client. 14 | type API struct { 15 | sc *Client 16 | } 17 | 18 | // NewAPI creates a new API for a storage client. 19 | func NewAPI(storageClient *Client) API { 20 | return API{sc: storageClient} 21 | } 22 | 23 | // ProposeStorageDeal calls the storage client ProposeDeal function 24 | func (a *API) ProposeStorageDeal(ctx context.Context, data cid.Cid, miner address.Address, 25 | askid uint64, duration uint64, allowDuplicates bool) (*storagedeal.SignedResponse, error) { 26 | 27 | return a.sc.ProposeDeal(ctx, miner, data, askid, duration, allowDuplicates) 28 | } 29 | 30 | // QueryStorageDeal calls the storage client QueryDeal function 31 | func (a *API) QueryStorageDeal(ctx context.Context, prop cid.Cid) (*storagedeal.SignedResponse, error) { 32 | return a.sc.QueryDeal(ctx, prop) 33 | } 34 | 35 | // Payments calls the storage client LoadVouchersForDeal function 36 | func (a *API) Payments(ctx context.Context, dealCid cid.Cid) ([]*types.PaymentVoucher, error) { 37 | return a.sc.LoadVouchersForDeal(ctx, dealCid) 38 | } 39 | -------------------------------------------------------------------------------- /protocol/storage/storage_protocol_test.go: -------------------------------------------------------------------------------- 1 | package storage_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/ipfs/go-cid" 7 | cbor "github.com/ipfs/go-ipld-cbor" 8 | 9 | "github.com/filecoin-project/go-filecoin/address" 10 | "github.com/filecoin-project/go-filecoin/protocol/storage/storagedeal" 11 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 12 | "github.com/filecoin-project/go-filecoin/types" 13 | "github.com/stretchr/testify/require" 14 | ) 15 | 16 | func TestSerializeProposal(t *testing.T) { 17 | tf.UnitTest(t) 18 | 19 | ag := address.NewForTestGetter() 20 | cg := types.NewCidForTestGetter() 21 | p := &storagedeal.Proposal{} 22 | p.Size = types.NewBytesAmount(5) 23 | cmc := cg() 24 | p.Payment.ChannelMsgCid = &cmc 25 | p.Payment.Channel = types.NewChannelID(4) 26 | voucher := &types.PaymentVoucher{ 27 | Channel: *types.NewChannelID(4), 28 | Payer: ag(), 29 | Target: ag(), 30 | Amount: types.NewAttoFILFromFIL(3), 31 | ValidAt: *types.NewBlockHeight(3), 32 | Signature: types.Signature{}, 33 | } 34 | p.Payment.Vouchers = []*types.PaymentVoucher{voucher} 35 | v, _ := cid.Decode("QmcrriCMhjb5ZWzmPNxmP53px47tSPcXBNaMtLdgcKFJYk") 36 | p.PieceRef = v 37 | chunk, err := cbor.DumpObject(p) 38 | require.NoError(t, err) 39 | 40 | err = cbor.DecodeInto(chunk, &storagedeal.Proposal{}) 41 | require.NoError(t, err) 42 | } 43 | -------------------------------------------------------------------------------- /protocol/storage/storagedeal/state.go: -------------------------------------------------------------------------------- 1 | package storagedeal 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // State signifies the state of a deal 8 | type State int 9 | 10 | const ( 11 | // Unset indicates a programmer error and should never appear in an actual message. 12 | Unset = State(iota) 13 | 14 | // Unknown signifies an unknown negotiation 15 | Unknown 16 | 17 | // Rejected means the deal was rejected for some reason 18 | Rejected 19 | 20 | // Accepted means the deal was accepted but hasnt yet started 21 | Accepted 22 | 23 | // Started means the deal has started and the transfer is in progress 24 | Started 25 | 26 | // Failed means the deal has failed for some reason 27 | Failed 28 | 29 | // Staged means that data has been received and staged into a sector, but is not sealed yet. 30 | Staged 31 | 32 | // Complete means that the sector that the deal is contained in has been sealed and its commitment posted on chain. 33 | Complete 34 | ) 35 | 36 | func (s State) String() string { 37 | switch s { 38 | case Unset: 39 | return "unset" 40 | case Unknown: 41 | return "unknown" 42 | case Rejected: 43 | return "rejected" 44 | case Accepted: 45 | return "accepted" 46 | case Started: 47 | return "started" 48 | case Failed: 49 | return "failed" 50 | case Staged: 51 | return "staged" 52 | case Complete: 53 | return "complete" 54 | default: 55 | return fmt.Sprintf("", s) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /protocol/storage/testing.go: -------------------------------------------------------------------------------- 1 | package storage 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/types" 7 | ) 8 | 9 | // FakeProver provides fake PoSt proofs for a miner. 10 | type FakeProver struct{} 11 | 12 | // CalculatePoSt returns a fixed fake proof. 13 | func (p *FakeProver) CalculatePoSt(ctx context.Context, start, end *types.BlockHeight, inputs []PoStInputs) (*PoStSubmission, error) { 14 | return &PoStSubmission{ 15 | Proof: []byte("test proof"), 16 | }, nil 17 | } 18 | -------------------------------------------------------------------------------- /repo/repo.go: -------------------------------------------------------------------------------- 1 | package repo 2 | 3 | import ( 4 | "github.com/ipfs/go-datastore" 5 | keystore "github.com/ipfs/go-ipfs-keystore" 6 | 7 | "github.com/filecoin-project/go-filecoin/config" 8 | ) 9 | 10 | // Version is the version of repo schema that this code understands. 11 | const Version uint = 2 12 | 13 | // Datastore is the datastore interface provided by the repo 14 | type Datastore interface { 15 | // NB: there are other more featureful interfaces we could require here, we 16 | // can either force it, or just do hopeful type checks. Not all datastores 17 | // implement every feature. 18 | datastore.Batching 19 | } 20 | 21 | // Repo is a representation of all persistent data in a filecoin node. 22 | type Repo interface { 23 | Config() *config.Config 24 | // ReplaceConfig replaces the current config, with the newly passed in one. 25 | ReplaceConfig(cfg *config.Config) error 26 | 27 | // Datastore is a general storage solution for things like blocks. 28 | Datastore() Datastore 29 | Keystore() keystore.Keystore 30 | 31 | // WalletDatastore is a specific storage solution, only used to store sensitive wallet information. 32 | WalletDatastore() Datastore 33 | 34 | // ChainDatastore is a specific storage solution, only used to store already validated chain data. 35 | ChainDatastore() Datastore 36 | 37 | // DealsDatastore holds deals data. 38 | DealsDatastore() Datastore 39 | 40 | // SetAPIAddr sets the address of the running API. 41 | SetAPIAddr(string) error 42 | 43 | // APIAddr returns the address of the running API. 44 | APIAddr() (string, error) 45 | 46 | // Version returns the current repo version. 47 | Version() uint 48 | 49 | // Path returns the repo path. 50 | Path() (string, error) 51 | 52 | // Close shuts down the repo. 53 | Close() error 54 | } 55 | -------------------------------------------------------------------------------- /repo/testing.go: -------------------------------------------------------------------------------- 1 | package repo 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | // RequireMakeTempDir ensures that a temporary directory is created 12 | func RequireMakeTempDir(t *testing.T, dirname string) string { 13 | newdir, err := ioutil.TempDir("", dirname) 14 | require.NoError(t, err) 15 | return newdir 16 | } 17 | 18 | // RequireRemoveAll ensures that the error condition is checked when we clean up 19 | // after creating a temporary directory. 20 | func RequireRemoveAll(t *testing.T, path string) { 21 | require.NoError(t, os.RemoveAll(path)) 22 | } 23 | 24 | // RequireOpenTempFile is a shortcut for opening a given temp file with a given 25 | // suffix, then returning both a filename and a file pointer. 26 | func RequireOpenTempFile(t *testing.T, suffix string) (*os.File, string) { 27 | file, err := ioutil.TempFile("", suffix) 28 | require.NoError(t, err) 29 | name := file.Name() 30 | return file, name 31 | } 32 | 33 | // RequireReadLink reads a symlink that is expected to resolve successfully. 34 | func RequireReadLink(t *testing.T, path string) string { 35 | target, err := os.Readlink(path) 36 | require.NoError(t, err) 37 | return target 38 | } 39 | -------------------------------------------------------------------------------- /scripts/build-bundle.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SHORT_GIT_SHA=${CIRCLE_SHA1:0:6} 4 | RELEASE_TAG="${CIRCLE_TAG:-$SHORT_GIT_SHA}" 5 | 6 | mkdir bundle 7 | pushd bundle 8 | mkdir -p filecoin 9 | 10 | # binary 11 | cp ../go-filecoin filecoin/ 12 | chmod +x filecoin/go-filecoin 13 | 14 | # proof params data 15 | cp ../go-sectorbuilder/paramcache filecoin/ 16 | chmod +x filecoin/paramcache 17 | 18 | tar -zcvf "filecoin-$RELEASE_TAG-`uname`.tar.gz" filecoin 19 | rm -rf filecoin 20 | 21 | popd 22 | -------------------------------------------------------------------------------- /scripts/install-filecoin-parameters.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -Eeo pipefail 4 | 5 | generate_params() { 6 | # The `--test-only` flag will cause paramcache to generate Groth parameters 7 | # and verifying keys for 1KiB sectors. If Groth parameters or verifying keys 8 | # for other sector sizes are needed, remove the `--test-only` flag. 9 | RUST_LOG=info ./go-sectorbuilder/paramcache --test-only 10 | } 11 | 12 | generate_params 13 | -------------------------------------------------------------------------------- /scripts/install-go-bls-sigs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -Eeo pipefail 4 | 5 | subm_dir="go-bls-sigs" 6 | 7 | git submodule update --init --recursive $subm_dir 8 | 9 | (cd ${subm_dir} ; make ;) -------------------------------------------------------------------------------- /scripts/install-go-sectorbuilder.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -Eeo pipefail 4 | 5 | subm_dir="go-sectorbuilder" 6 | 7 | git submodule update --init --recursive $subm_dir 8 | 9 | (cd ${subm_dir} ; make clean ; make) 10 | -------------------------------------------------------------------------------- /scripts/update-badge.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # this script updates go-filecoin status badges in https://github.com/filecoin-project/go-filecoin-badges 3 | # with latest binary release version 4 | set -e 5 | FILENAME="${1}" 6 | if [[ -z "${FILENAME}" ]]; then 7 | echo "filename argument must be provided" 8 | exit 1 9 | fi 10 | git config --global user.email dev-helper@filecoin.io 11 | git config --global user.name filecoin-helper 12 | git clone "https://${GITHUB_TOKEN}@github.com/filecoin-project/go-filecoin-badges.git" 13 | cd go-filecoin-badges 14 | jq --arg FILECOIN_BINARY_VERSION "${FILECOIN_BINARY_VERSION}" -r '.message = $FILECOIN_BINARY_VERSION' < "${FILENAME}" | tee "${FILENAME}.new" 15 | if [[ ! -s ${FILENAME}.new ]]; then 16 | echo "badge update was not successful. file is empty" 17 | exit 1 18 | fi 19 | mv "${FILENAME}.new" "${FILENAME}" 20 | git add "${FILENAME}" 21 | git commit -m "badge update bot: update ${FILENAME} to ${FILECOIN_BINARY_VERSION}" 22 | git push "https://${GITHUB_TOKEN}@github.com/filecoin-project/go-filecoin-badges.git" 23 | -------------------------------------------------------------------------------- /tools/fast/action_actor.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | "io" 6 | 7 | "github.com/filecoin-project/go-filecoin/commands" 8 | ) 9 | 10 | // ActorLs runs the `actor ls` command against the filecoin process. 11 | func (f *Filecoin) ActorLs(ctx context.Context) ([]commands.ActorView, error) { 12 | args := []string{"go-filecoin", "actor", "ls"} 13 | 14 | dec, err := f.RunCmdLDJSONWithStdin(ctx, nil, args...) 15 | if err != nil { 16 | return nil, err 17 | } 18 | 19 | views := []commands.ActorView{} 20 | for dec.More() { 21 | var view commands.ActorView 22 | err := dec.Decode(&view) 23 | if err != nil { 24 | if err == io.EOF { 25 | break 26 | } 27 | 28 | return nil, err 29 | } 30 | 31 | views = append(views, view) 32 | } 33 | 34 | return views, nil 35 | } 36 | -------------------------------------------------------------------------------- /tools/fast/action_address.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | "github.com/filecoin-project/go-filecoin/address" 6 | "github.com/filecoin-project/go-filecoin/commands" 7 | 8 | "github.com/libp2p/go-libp2p-core/peer" 9 | ) 10 | 11 | // AddressNew runs the address new command against the filecoin process. 12 | func (f *Filecoin) AddressNew(ctx context.Context) (address.Address, error) { 13 | var newAddress address.Address 14 | if err := f.RunCmdJSONWithStdin(ctx, nil, &newAddress, "go-filecoin", "address", "new"); err != nil { 15 | return address.Undef, err 16 | } 17 | return newAddress, nil 18 | } 19 | 20 | // AddressLs runs the address ls command against the filecoin process. 21 | func (f *Filecoin) AddressLs(ctx context.Context) ([]address.Address, error) { 22 | // the command returns an AddressListResult 23 | var alr commands.AddressLsResult 24 | // we expect to interact with an array of address 25 | var out []address.Address 26 | 27 | if err := f.RunCmdJSONWithStdin(ctx, nil, &alr, "go-filecoin", "address", "ls"); err != nil { 28 | return nil, err 29 | } 30 | 31 | // transform the AddressListResult to an array of addresses 32 | for _, addr := range alr.Addresses { 33 | a, err := address.NewFromString(addr) 34 | if err != nil { 35 | return nil, err 36 | } 37 | out = append(out, a) 38 | } 39 | return out, nil 40 | } 41 | 42 | // AddressLookup runs the address lookup command against the filecoin process. 43 | func (f *Filecoin) AddressLookup(ctx context.Context, addr address.Address) (peer.ID, error) { 44 | var ownerPeer peer.ID 45 | if err := f.RunCmdJSONWithStdin(ctx, nil, &ownerPeer, "go-filecoin", "address", "lookup", addr.String()); err != nil { 46 | return "", err 47 | } 48 | return ownerPeer, nil 49 | } 50 | -------------------------------------------------------------------------------- /tools/fast/action_bootstrap.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/commands" 7 | ) 8 | 9 | // BootstrapLs runs the `bootstrap ls` command against the filecoin process. 10 | func (f *Filecoin) BootstrapLs(ctx context.Context) (*commands.BootstrapLsResult, error) { 11 | var out commands.BootstrapLsResult 12 | args := []string{"go-filecoin", "bootstrap", "ls"} 13 | 14 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, args...); err != nil { 15 | return nil, err 16 | } 17 | 18 | return &out, nil 19 | 20 | } 21 | -------------------------------------------------------------------------------- /tools/fast/action_chain.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | 7 | "github.com/ipfs/go-cid" 8 | 9 | "github.com/filecoin-project/go-filecoin/chain" 10 | ) 11 | 12 | // ChainHead runs the chain head command against the filecoin process. 13 | func (f *Filecoin) ChainHead(ctx context.Context) ([]cid.Cid, error) { 14 | var out []cid.Cid 15 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, "go-filecoin", "chain", "head"); err != nil { 16 | return nil, err 17 | } 18 | return out, nil 19 | 20 | } 21 | 22 | // ChainLs runs the chain ls command against the filecoin process. 23 | func (f *Filecoin) ChainLs(ctx context.Context) (*json.Decoder, error) { 24 | return f.RunCmdLDJSONWithStdin(ctx, nil, "go-filecoin", "chain", "ls") 25 | } 26 | 27 | // ChainStatus runs the chain status command against the filecoin process. 28 | func (f *Filecoin) ChainStatus(ctx context.Context) (*chain.Status, error) { 29 | var out *chain.Status 30 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, "go-filecoin", "chain", "status"); err != nil { 31 | return nil, err 32 | } 33 | return out, nil 34 | } 35 | -------------------------------------------------------------------------------- /tools/fast/action_config.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | ) 8 | 9 | // ConfigGet runs the `config` command against the filecoin process, and decodes the 10 | // output into `v`. 11 | func (f *Filecoin) ConfigGet(ctx context.Context, key string, v interface{}) error { 12 | args := []string{"go-filecoin", "config", key} 13 | 14 | if err := f.RunCmdJSONWithStdin(ctx, nil, v, args...); err != nil { 15 | return err 16 | } 17 | 18 | return nil 19 | } 20 | 21 | // ConfigSet runs the `config` command against the filecoin process, encoding `v` as 22 | // the value. 23 | func (f *Filecoin) ConfigSet(ctx context.Context, key string, v interface{}) error { 24 | value, err := json.Marshal(v) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | args := []string{"go-filecoin", "config", key, string(value)} 30 | 31 | out, err := f.RunCmdWithStdin(ctx, nil, args...) 32 | if err != nil { 33 | return err 34 | } 35 | 36 | // check command exit code 37 | if out.ExitCode() > 0 { 38 | return fmt.Errorf("filecoin command: %s, exited with non-zero exitcode: %d", out.Args(), out.ExitCode()) 39 | } 40 | 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /tools/fast/action_dag.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | 6 | cid "github.com/ipfs/go-cid" 7 | ) 8 | 9 | // DagGet runs the `dag get` command against the filecoin process 10 | func (f *Filecoin) DagGet(ctx context.Context, ref cid.Cid) (map[string]interface{}, error) { 11 | var out map[string]interface{} 12 | 13 | sRef := ref.String() 14 | 15 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, "go-filecoin", "dag", "get", sRef); err != nil { 16 | return nil, err 17 | } 18 | 19 | return out, nil 20 | } 21 | -------------------------------------------------------------------------------- /tools/fast/action_deals.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | 7 | "github.com/ipfs/go-cid" 8 | 9 | "github.com/filecoin-project/go-filecoin/commands" 10 | ) 11 | 12 | // DealsList runs the `deals list` command against the filecoin process 13 | func (f *Filecoin) DealsList(ctx context.Context, options ...ActionOption) (*json.Decoder, error) { 14 | args := []string{"go-filecoin", "deals", "list"} 15 | 16 | for _, option := range options { 17 | args = append(args, option()...) 18 | } 19 | 20 | return f.RunCmdLDJSONWithStdin(ctx, nil, args...) 21 | } 22 | 23 | // DealsRedeem runs the `deals redeem` command against the filecoin process. 24 | func (f *Filecoin) DealsRedeem(ctx context.Context, dealCid cid.Cid, options ...ActionOption) (cid.Cid, error) { 25 | var out commands.RedeemResult 26 | args := []string{"go-filecoin", "deals", "redeem", dealCid.String()} 27 | 28 | for _, option := range options { 29 | args = append(args, option()...) 30 | } 31 | 32 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, args...); err != nil { 33 | return cid.Undef, err 34 | } 35 | 36 | return out.Cid, nil 37 | } 38 | 39 | // DealsShow runs the `deals show` command against the filecoin process 40 | func (f *Filecoin) DealsShow(ctx context.Context, propCid cid.Cid) (*commands.DealsShowResult, error) { 41 | 42 | var out commands.DealsShowResult 43 | 44 | err := f.RunCmdJSONWithStdin(ctx, nil, &out, "go-filecoin", "deals", "show", propCid.String()) 45 | if err != nil { 46 | return nil, err 47 | } 48 | return &out, nil 49 | } 50 | -------------------------------------------------------------------------------- /tools/fast/action_dht.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "io" 7 | 8 | "github.com/ipfs/go-cid" 9 | "github.com/libp2p/go-libp2p-core/peer" 10 | "github.com/multiformats/go-multiaddr" 11 | ) 12 | 13 | // DHTFindPeer runs the `dht findpeer` command against the filecoin process 14 | func (f *Filecoin) DHTFindPeer(ctx context.Context, pid peer.ID) ([]multiaddr.Multiaddr, error) { 15 | decoder, err := f.RunCmdLDJSONWithStdin(ctx, nil, "go-filecoin", "dht", "findpeer", pid.String()) 16 | if err != nil { 17 | return nil, err 18 | } 19 | 20 | var out []multiaddr.Multiaddr 21 | for { 22 | var addr string 23 | if err := decoder.Decode(&addr); err != nil { 24 | if err == io.EOF { 25 | break 26 | } 27 | 28 | return []multiaddr.Multiaddr{}, err 29 | } 30 | 31 | ma, err := multiaddr.NewMultiaddr(addr) 32 | if err != nil { 33 | return []multiaddr.Multiaddr{}, err 34 | } 35 | 36 | out = append(out, ma) 37 | } 38 | 39 | return out, nil 40 | } 41 | 42 | // DHTFindProvs runs the `dht findprovs` command against the filecoin process 43 | func (f *Filecoin) DHTFindProvs(ctx context.Context, key cid.Cid) (*json.Decoder, error) { 44 | args := []string{"go-filecoin", "dht", "findprovs", key.String()} 45 | return f.RunCmdLDJSONWithStdin(ctx, nil, args...) 46 | } 47 | -------------------------------------------------------------------------------- /tools/fast/action_id.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/commands" 7 | ) 8 | 9 | // ID runs the `id` command against the filecoin process 10 | func (f *Filecoin) ID(ctx context.Context, options ...ActionOption) (*commands.IDDetails, error) { 11 | var out commands.IDDetails 12 | args := []string{"go-filecoin", "id"} 13 | 14 | for _, option := range options { 15 | args = append(args, option()...) 16 | } 17 | 18 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, args...); err != nil { 19 | return nil, err 20 | } 21 | 22 | return &out, nil 23 | } 24 | -------------------------------------------------------------------------------- /tools/fast/action_message.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | 6 | cid "github.com/ipfs/go-cid" 7 | 8 | "github.com/filecoin-project/go-filecoin/address" 9 | "github.com/filecoin-project/go-filecoin/commands" 10 | ) 11 | 12 | // MessageSend runs the `message send` command against the filecoin process. 13 | func (f *Filecoin) MessageSend(ctx context.Context, target address.Address, method string, options ...ActionOption) (cid.Cid, error) { 14 | var out commands.MessageSendResult 15 | 16 | args := []string{"go-filecoin", "message", "send"} 17 | 18 | for _, option := range options { 19 | args = append(args, option()...) 20 | } 21 | 22 | args = append(args, target.String()) 23 | 24 | if method != "" { 25 | args = append(args, method) 26 | } 27 | 28 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, args...); err != nil { 29 | return cid.Undef, err 30 | } 31 | 32 | return out.Cid, nil 33 | } 34 | 35 | // MessageWait runs the `message wait` command against the filecoin process. 36 | func (f *Filecoin) MessageWait(ctx context.Context, mcid cid.Cid, options ...ActionOption) (commands.WaitResult, error) { 37 | var out commands.WaitResult 38 | 39 | args := []string{"go-filecoin", "message", "wait"} 40 | 41 | for _, option := range options { 42 | args = append(args, option()...) 43 | } 44 | 45 | args = append(args, mcid.String()) 46 | 47 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, args...); err != nil { 48 | return commands.WaitResult{}, err 49 | } 50 | 51 | return out, nil 52 | } 53 | -------------------------------------------------------------------------------- /tools/fast/action_mpool.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/types" 7 | ) 8 | 9 | // MpoolLs runs the `mpool ls` command against the filecoin process. 10 | func (f *Filecoin) MpoolLs(ctx context.Context, options ...ActionOption) ([]*types.SignedMessage, error) { 11 | var out []*types.SignedMessage 12 | 13 | args := []string{"go-filecoin", "mpool", "ls"} 14 | 15 | for _, option := range options { 16 | args = append(args, option()...) 17 | } 18 | 19 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, args...); err != nil { 20 | return []*types.SignedMessage{}, err 21 | } 22 | 23 | return out, nil 24 | } 25 | -------------------------------------------------------------------------------- /tools/fast/action_ping.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | "io" 6 | 7 | "github.com/libp2p/go-libp2p-core/peer" 8 | 9 | "github.com/filecoin-project/go-filecoin/commands" 10 | ) 11 | 12 | // Ping runs the `ping` command against the filecoin process 13 | func (f *Filecoin) Ping(ctx context.Context, pid peer.ID, options ...ActionOption) ([]commands.PingResult, error) { 14 | sPid := pid.Pretty() 15 | 16 | args := []string{"go-filecoin", "ping"} 17 | 18 | for _, option := range options { 19 | args = append(args, option()...) 20 | } 21 | 22 | args = append(args, sPid) 23 | 24 | decoder, err := f.RunCmdLDJSONWithStdin(ctx, nil, args...) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | var out []commands.PingResult 30 | 31 | for { 32 | var result commands.PingResult 33 | if err := decoder.Decode(&result); err != nil { 34 | if err == io.EOF { 35 | break 36 | } 37 | 38 | return []commands.PingResult{}, err 39 | } 40 | 41 | out = append(out, result) 42 | } 43 | 44 | return out, nil 45 | } 46 | -------------------------------------------------------------------------------- /tools/fast/action_protocol.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/porcelain" 7 | ) 8 | 9 | // Protocol runs the `protocol` command against the filecoin process 10 | func (f *Filecoin) Protocol(ctx context.Context) (*porcelain.ProtocolParams, error) { 11 | var out porcelain.ProtocolParams 12 | 13 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, "go-filecoin", "protocol"); err != nil { 14 | return nil, err 15 | } 16 | 17 | return &out, nil 18 | } 19 | -------------------------------------------------------------------------------- /tools/fast/action_retrieval_client.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | 8 | "github.com/ipfs/go-cid" 9 | 10 | "github.com/filecoin-project/go-filecoin/address" 11 | ) 12 | 13 | // RetrievalClientRetrievePiece runs the retrieval-client retrieve-piece commands against the filecoin process. 14 | func (f *Filecoin) RetrievalClientRetrievePiece(ctx context.Context, pieceCID cid.Cid, minerAddr address.Address) (io.ReadCloser, error) { 15 | out, err := f.RunCmdWithStdin(ctx, nil, "go-filecoin", "retrieval-client", "retrieve-piece", minerAddr.String(), pieceCID.String()) 16 | if err != nil { 17 | return nil, err 18 | } 19 | if out.ExitCode() > 0 { 20 | return nil, fmt.Errorf("filecoin command: %s, exited with non-zero exitcode: %d", out.Args(), out.ExitCode()) 21 | } 22 | return out.Stdout(), nil 23 | } 24 | -------------------------------------------------------------------------------- /tools/fast/action_show.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/ipfs/go-cid" 7 | 8 | "github.com/filecoin-project/go-filecoin/types" 9 | ) 10 | 11 | // ShowHeader runs the `show header` command against the filecoin process 12 | func (f *Filecoin) ShowHeader(ctx context.Context, ref cid.Cid) (*types.Block, error) { 13 | var out types.Block 14 | 15 | sRef := ref.String() 16 | 17 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, "go-filecoin", "show", "header", sRef); err != nil { 18 | return nil, err 19 | } 20 | 21 | return &out, nil 22 | } 23 | 24 | // ShowMessages runs the `show messages` command against the filecoin process 25 | func (f *Filecoin) ShowMessages(ctx context.Context, ref cid.Cid) ([]*types.SignedMessage, error) { 26 | var out []*types.SignedMessage 27 | 28 | sRef := ref.String() 29 | 30 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, "go-filecoin", "show", "messages", sRef); err != nil { 31 | return nil, err 32 | } 33 | 34 | return out, nil 35 | } 36 | 37 | // ShowReceipts runs the `show receipts` command against the filecoin process 38 | func (f *Filecoin) ShowReceipts(ctx context.Context, ref cid.Cid) ([]*types.MessageReceipt, error) { 39 | var out []*types.MessageReceipt 40 | 41 | sRef := ref.String() 42 | 43 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, "go-filecoin", "show", "receipts", sRef); err != nil { 44 | return nil, err 45 | } 46 | 47 | return out, nil 48 | } 49 | -------------------------------------------------------------------------------- /tools/fast/action_swarm.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/libp2p/go-libp2p-core/peer" 7 | "github.com/multiformats/go-multiaddr" 8 | 9 | "github.com/filecoin-project/go-filecoin/net" 10 | ) 11 | 12 | // SwarmConnect runs the `swarm connect` command against the filecoin process 13 | func (f *Filecoin) SwarmConnect(ctx context.Context, addrs ...multiaddr.Multiaddr) (peer.ID, error) { 14 | var out peer.ID 15 | 16 | args := []string{"go-filecoin", "swarm", "connect"} 17 | 18 | for _, addr := range addrs { 19 | args = append(args, addr.String()) 20 | } 21 | 22 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, args...); err != nil { 23 | return peer.ID(""), err 24 | } 25 | 26 | return out, nil 27 | } 28 | 29 | // SwarmPeers runs the `swarm peers` command against the filecoin process 30 | func (f *Filecoin) SwarmPeers(ctx context.Context, options ...ActionOption) ([]net.SwarmConnInfo, error) { 31 | var out net.SwarmConnInfos 32 | 33 | args := []string{"go-filecoin", "swarm", "peers"} 34 | 35 | for _, option := range options { 36 | args = append(args, option()...) 37 | } 38 | 39 | if err := f.RunCmdJSONWithStdin(ctx, nil, &out, args...); err != nil { 40 | return nil, err 41 | } 42 | 43 | return out.Peers, nil 44 | } 45 | -------------------------------------------------------------------------------- /tools/fast/fastesting/assertions.go: -------------------------------------------------------------------------------- 1 | package fastesting 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | 11 | "github.com/filecoin-project/go-filecoin/tools/fast" 12 | ) 13 | 14 | // AssertStdErrContains verifies that the last command stderr of 'fast' contains the 15 | // string 'expected' 16 | func AssertStdErrContains(t *testing.T, fast *fast.Filecoin, expected string) { 17 | var cmdOutBytes []byte 18 | w := bytes.NewBuffer(cmdOutBytes) 19 | written, err := io.Copy(w, fast.LastCmdStdErr()) 20 | require.NoError(t, err) 21 | require.True(t, written > 0) 22 | assert.Contains(t, string(w.Bytes()), expected) 23 | } 24 | -------------------------------------------------------------------------------- /tools/fast/fastesting/basic_test.go: -------------------------------------------------------------------------------- 1 | package fastesting_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | 8 | "github.com/ipfs/go-log" 9 | "github.com/stretchr/testify/require" 10 | 11 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 12 | "github.com/filecoin-project/go-filecoin/tools/fast" 13 | "github.com/filecoin-project/go-filecoin/tools/fast/fastesting" 14 | ) 15 | 16 | func TestSetFilecoinOpts(t *testing.T) { 17 | tf.IntegrationTest(t) 18 | log.SetDebugLogging() 19 | 20 | fastOpts := fast.FilecoinOpts{ 21 | DaemonOpts: []fast.ProcessDaemonOption{fast.POBlockTime(10 * time.Millisecond)}, 22 | } 23 | 24 | ctx, env := fastesting.NewTestEnvironment(context.Background(), t, fastOpts) 25 | 26 | clientNode := env.GenesisMiner 27 | require.NoError(t, clientNode.MiningStart(ctx)) 28 | defer func() { 29 | err := env.Teardown(ctx) 30 | require.NoError(t, err) 31 | }() 32 | } 33 | 34 | func TestNoFilecoinOpts(t *testing.T) { 35 | tf.IntegrationTest(t) 36 | log.SetDebugLogging() 37 | 38 | ctx, env := fastesting.NewTestEnvironment(context.Background(), t, fast.FilecoinOpts{}) 39 | 40 | clientNode := env.GenesisMiner 41 | require.NoError(t, clientNode.MiningStart(ctx)) 42 | defer func() { 43 | err := env.Teardown(ctx) 44 | require.NoError(t, err) 45 | }() 46 | } 47 | -------------------------------------------------------------------------------- /tools/fast/fastesting/log_writer.go: -------------------------------------------------------------------------------- 1 | package fastesting 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | "sync" 7 | ) 8 | 9 | type logWriter struct { 10 | bpr *bufio.Reader 11 | pw io.WriteCloser 12 | wg sync.WaitGroup 13 | out logf 14 | } 15 | 16 | type logf interface { 17 | Logf(string, ...interface{}) 18 | } 19 | 20 | // newLogWriter returns a io.WriteCloser which will take all lines written to 21 | // it and call out.Logf with it. This is currently used with the FAST DumpLastOutput 22 | // to print the output of a command to the test logger. 23 | func newLogWriter(out logf) io.WriteCloser { 24 | pr, pw := io.Pipe() 25 | bpr := bufio.NewReader(pr) 26 | 27 | p := &logWriter{ 28 | pw: pw, 29 | bpr: bpr, 30 | out: out, 31 | } 32 | 33 | p.wg.Add(1) 34 | go p.writeOut() 35 | 36 | return p 37 | } 38 | 39 | func (p *logWriter) writeOut() { 40 | defer p.wg.Done() 41 | for { 42 | l, err := p.bpr.ReadBytes('\n') 43 | if len(l) != 0 { 44 | p.out.Logf(string(l)) 45 | } 46 | if err != nil { 47 | break 48 | } 49 | } 50 | } 51 | 52 | // Write the bytes b using t.Logf on each full line 53 | func (p *logWriter) Write(b []byte) (int, error) { 54 | return p.pw.Write(b) 55 | } 56 | 57 | // Close the writer 58 | func (p *logWriter) Close() error { 59 | err := p.pw.Close() 60 | p.wg.Wait() 61 | return err 62 | } 63 | -------------------------------------------------------------------------------- /tools/fast/fastesting/log_writer_test.go: -------------------------------------------------------------------------------- 1 | package fastesting 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strings" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/require" 10 | 11 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 12 | ) 13 | 14 | type tlogWriter struct { 15 | buf bytes.Buffer 16 | } 17 | 18 | func (w *tlogWriter) Logf(format string, args ...interface{}) { 19 | fmt.Fprintf(&w.buf, format, args...) 20 | } 21 | 22 | func TestLogWriter(t *testing.T) { 23 | tf.UnitTest(t) 24 | 25 | input := []string{ 26 | "line1\n", 27 | "line2\n", 28 | "line3\n", 29 | "line4\n", 30 | "line5\n", 31 | } 32 | 33 | out := &tlogWriter{} 34 | lw := newLogWriter(out) 35 | 36 | for _, line := range input { 37 | _, err := lw.Write([]byte(fmt.Sprintf("%s", line))) 38 | require.NoError(t, err) 39 | } 40 | 41 | require.NoError(t, lw.Close()) 42 | 43 | require.Equal(t, strings.Join(input, ""), out.buf.String()) 44 | } 45 | -------------------------------------------------------------------------------- /tools/fast/fastutil/helpers_test.go: -------------------------------------------------------------------------------- 1 | package fastutil 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "strings" 8 | "testing" 9 | 10 | "github.com/pmezard/go-difflib/difflib" 11 | ) 12 | 13 | func writeLine(seed int, ws ...io.Writer) error { 14 | alphabet := "0123456789ABCDEF" 15 | var line strings.Builder 16 | for x := 0; x < 64; x++ { 17 | c := alphabet[(x+seed)%len(alphabet)] 18 | line.WriteByte(c) 19 | } 20 | 21 | line.WriteByte('\n') 22 | 23 | for _, w := range ws { 24 | n, err := w.Write([]byte(line.String())) 25 | 26 | if err != nil { 27 | return err 28 | } 29 | 30 | if n != line.Len() { 31 | return fmt.Errorf("did not write entire line") 32 | } 33 | 34 | } 35 | 36 | return nil 37 | } 38 | 39 | func compare(t *testing.T, expected, actual []byte) { 40 | if !bytes.Equal(expected, actual) { 41 | diff := difflib.UnifiedDiff{ 42 | A: difflib.SplitLines(string(expected)), 43 | B: difflib.SplitLines(string(actual)), 44 | FromFile: "Expected", 45 | ToFile: "Actual", 46 | Context: 3, 47 | } 48 | text, _ := difflib.GetUnifiedDiffString(diff) 49 | 50 | t.Logf("\n%s", text) 51 | t.Fatal("data does not match") 52 | } 53 | } 54 | 55 | func writeLines(seed int, num int, ws ...io.Writer) error { 56 | for i := 0; i < num; i++ { 57 | if err := writeLine(seed+i, ws...); err != nil { 58 | return err 59 | } 60 | } 61 | 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /tools/fast/fastutil/line_puller.go: -------------------------------------------------------------------------------- 1 | package fastutil 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | "io" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | // LinePuller provides an easy way to pull complete lines (ending in \n) from 12 | // a source to a sink. 13 | type LinePuller struct { 14 | sourceMu sync.Mutex 15 | source *bufio.Reader 16 | sink io.Writer 17 | } 18 | 19 | // NewLinePuller returns a LinePuller that will read complete lines 20 | // from the source to the sink when started (see Start) on the provided 21 | // frequency. 22 | func NewLinePuller(source io.Reader, sink io.Writer) *LinePuller { 23 | return &LinePuller{ 24 | source: bufio.NewReader(source), 25 | sink: sink, 26 | } 27 | } 28 | 29 | // StartPulling will call Pull on an interval of freq. 30 | func (lp *LinePuller) StartPulling(ctx context.Context, freq time.Duration) error { 31 | ticker := time.NewTicker(freq) 32 | for { 33 | select { 34 | case <-ctx.Done(): 35 | return ctx.Err() 36 | case <-ticker.C: 37 | if err := lp.Pull(); err != nil { 38 | return err 39 | } 40 | } 41 | } 42 | } 43 | 44 | // Pull reads in all data from the source and writes each line out to the sink. 45 | func (lp *LinePuller) Pull() error { 46 | lp.sourceMu.Lock() 47 | defer lp.sourceMu.Unlock() 48 | for { 49 | line, rerr := lp.source.ReadBytes('\n') 50 | if rerr != nil && rerr != io.EOF { 51 | return rerr 52 | } 53 | 54 | _, err := lp.sink.Write(line) 55 | if err != nil { 56 | return err 57 | } 58 | 59 | if rerr == io.EOF { 60 | return nil 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tools/fast/process_stderr_recorder.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/filecoin-project/go-filecoin/tools/fast/fastutil" 8 | ) 9 | 10 | // setupStderrCpaturing opens a reader to the filcoin process to read the stderr 11 | // and then builds a LinePuller to read each line from stderr. This will ensure 12 | // that only complete lines are written to the IntervalRecorder, so that the 13 | // intervals we capture always contain complete log lines 14 | func (f *Filecoin) setupStderrCapturing() error { 15 | stderr, err := f.core.StderrReader() 16 | if err != nil { 17 | return err 18 | } 19 | 20 | f.stderr = stderr 21 | 22 | f.lp = fastutil.NewLinePuller(stderr, &f.ir) 23 | f.lpCtx, f.lpCancel = context.WithCancel(f.ctx) 24 | 25 | go func(ctx context.Context) { 26 | err := f.lp.StartPulling(ctx, time.Millisecond*10) 27 | if err == nil || err == context.Canceled || err == context.DeadlineExceeded { 28 | return 29 | } 30 | 31 | f.Log.Errorf("Stderr log capture failed with error: %s") 32 | f.lpErr = err 33 | }(f.lpCtx) 34 | 35 | return nil 36 | } 37 | 38 | func (f *Filecoin) teardownStderrCapturing() error { 39 | if f.lp != nil { 40 | f.lpCancel() 41 | } 42 | if f.stderr != nil { 43 | return f.stderr.Close() 44 | } 45 | return nil 46 | } 47 | 48 | // StartLogCapture returns a fastutil.Interval, after calling fastutil.Interval#Stop 49 | // all stderr logs generator between the call to StartLogCapture and then will 50 | // be available. fastutil.Interval implements io.Reader (its a bytes.Buffer) 51 | // If an error has occurred reading the stderr, the error will be returned here 52 | func (f *Filecoin) StartLogCapture() (*fastutil.Interval, error) { 53 | if f.lpErr != nil { 54 | return nil, f.lpErr 55 | } 56 | 57 | return f.ir.Start(), nil 58 | } 59 | -------------------------------------------------------------------------------- /tools/fast/process_stderr_recorder_test.go: -------------------------------------------------------------------------------- 1 | package fast 2 | 3 | import ( 4 | "context" 5 | "io/ioutil" 6 | "testing" 7 | 8 | iptb "github.com/ipfs/iptb/testbed" 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | 12 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 13 | mockplugin "github.com/filecoin-project/go-filecoin/tools/iptb-plugins/filecoin/mock" 14 | ) 15 | 16 | func TestStartLogCapture(t *testing.T) { 17 | tf.UnitTest(t) 18 | 19 | ctx := context.Background() 20 | dir := "mockdir" 21 | 22 | ns := iptb.NodeSpec{ 23 | Type: mockplugin.PluginName, 24 | Dir: dir, 25 | Attrs: nil, 26 | } 27 | 28 | c, err := ns.Load() 29 | assert.NoError(t, err) 30 | 31 | fc, ok := c.(IPTBCoreExt) 32 | require.True(t, ok) 33 | 34 | mfc := NewFilecoinProcess(ctx, fc, FilecoinOpts{}) 35 | err = mfc.setupStderrCapturing() 36 | require.NoError(t, err) 37 | 38 | t.Run("test capture logs", func(t *testing.T) { 39 | capture, err := mfc.StartLogCapture() 40 | require.NoError(t, err) 41 | 42 | _, err = mfc.RunCmdWithStdin(ctx, nil, "add-to-daemonstderr", "hello") 43 | require.NoError(t, err) 44 | 45 | err = mfc.lp.Pull() 46 | require.NoError(t, err) 47 | 48 | capture.Stop() 49 | 50 | bb, err := ioutil.ReadAll(capture) 51 | require.NoError(t, err) 52 | 53 | require.Equal(t, "hello\n", string(bb)) 54 | }) 55 | 56 | err = mfc.teardownStderrCapturing() 57 | require.NoError(t, err) 58 | } 59 | -------------------------------------------------------------------------------- /tools/fast/series/connect.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/tools/fast" 7 | ) 8 | 9 | // Connect issues a `swarm connect` to the `from` node, using the addresses of the `to` node 10 | func Connect(ctx context.Context, from, to *fast.Filecoin) error { 11 | details, err := to.ID(ctx) 12 | if err != nil { 13 | return err 14 | } 15 | 16 | if _, err := from.SwarmConnect(ctx, details.Addresses...); err != nil { 17 | return err 18 | } 19 | 20 | return nil 21 | } 22 | -------------------------------------------------------------------------------- /tools/fast/series/create_miner_with_ask.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | "math/big" 6 | 7 | "github.com/filecoin-project/go-filecoin/porcelain" 8 | "github.com/filecoin-project/go-filecoin/tools/fast" 9 | "github.com/filecoin-project/go-filecoin/types" 10 | ) 11 | 12 | // CreateStorageMinerWithAsk setups a miner and sets an ask price. The created ask is 13 | // returned. 14 | func CreateStorageMinerWithAsk(ctx context.Context, miner *fast.Filecoin, collateral *big.Int, price *big.Float, expiry *big.Int, sectorSize *types.BytesAmount) (porcelain.Ask, error) { 15 | // Create miner 16 | _, err := miner.MinerCreate(ctx, collateral, fast.AOSectorSize(sectorSize), fast.AOPrice(big.NewFloat(1.0)), fast.AOLimit(300)) 17 | if err != nil { 18 | return porcelain.Ask{}, err 19 | } 20 | 21 | return SetPriceGetAsk(ctx, miner, price, expiry) 22 | } 23 | -------------------------------------------------------------------------------- /tools/fast/series/ctx_sleep_delay.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "github.com/filecoin-project/go-filecoin/consensus" 8 | ) 9 | 10 | type ctxSleepDelayKey struct{} 11 | 12 | var ( 13 | // Key used to set the time.Duration in the context 14 | sleepDelayKey = ctxSleepDelayKey{} 15 | 16 | // Default delay 17 | defaultSleepDelay = consensus.DefaultBlockTime 18 | ) 19 | 20 | // SetCtxSleepDelay returns a context with `d` set in the context. To sleep with 21 | // the value, call CtxSleepDelay with the context. 22 | func SetCtxSleepDelay(ctx context.Context, d time.Duration) context.Context { 23 | return context.WithValue(ctx, sleepDelayKey, d) 24 | } 25 | 26 | // CtxSleepDelay is a helper method to make sure people don't call `time.Sleep` 27 | // or `time.After` themselves in series. It will use the time.Duration in the 28 | // context, or default to `mining.DefaultBlockTime` from the go-filecoin/mining package. 29 | // A channel is return which will receive a time.Time value after the delay. 30 | func CtxSleepDelay(ctx context.Context) <-chan time.Time { 31 | d, ok := ctx.Value(sleepDelayKey).(time.Duration) 32 | if !ok { 33 | d = defaultSleepDelay 34 | } 35 | 36 | return time.After(d) 37 | } 38 | -------------------------------------------------------------------------------- /tools/fast/series/find_deal_by_id.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/filecoin-project/go-filecoin/commands" 8 | "github.com/filecoin-project/go-filecoin/tools/fast" 9 | "github.com/ipfs/go-cid" 10 | ) 11 | 12 | // FindDealByID looks for a deal using `DealsList` and returns the result where id matches the ProposalCid of 13 | // the deal. 14 | func FindDealByID(ctx context.Context, client *fast.Filecoin, id cid.Cid) (commands.DealsListResult, error) { 15 | dec, err := client.DealsList(ctx) 16 | if err != nil { 17 | return commands.DealsListResult{}, err 18 | } 19 | 20 | var dl commands.DealsListResult 21 | 22 | for dec.More() { 23 | if err := dec.Decode(&dl); err != nil { 24 | return commands.DealsListResult{}, err 25 | } 26 | 27 | if dl.ProposalCid == id { 28 | return dl, nil 29 | } 30 | } 31 | 32 | return commands.DealsListResult{}, fmt.Errorf("No deal found") 33 | } 34 | -------------------------------------------------------------------------------- /tools/fast/series/get_head_block_height.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/tools/fast" 7 | "github.com/filecoin-project/go-filecoin/types" 8 | ) 9 | 10 | // GetHeadBlockHeight will inspect the chain head and return the height 11 | func GetHeadBlockHeight(ctx context.Context, client *fast.Filecoin) (*types.BlockHeight, error) { 12 | tipset, err := client.ChainHead(ctx) 13 | if err != nil { 14 | return nil, err 15 | } 16 | 17 | block, err := client.ShowHeader(ctx, tipset[0]) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | return types.NewBlockHeight(uint64(block.Height)), nil 23 | } 24 | -------------------------------------------------------------------------------- /tools/fast/series/import_and_store.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/protocol/storage/storagedeal" 7 | 8 | "github.com/ipfs/go-cid" 9 | "github.com/ipfs/go-ipfs-files" 10 | 11 | "github.com/filecoin-project/go-filecoin/porcelain" 12 | "github.com/filecoin-project/go-filecoin/tools/fast" 13 | ) 14 | 15 | // ImportAndStore imports the `data` to the `client`, and proposes a storage 16 | // deal using the provided `ask`, returning the cid of the import and the 17 | // created deal. It uses a duration of 10 blocks 18 | func ImportAndStore(ctx context.Context, client *fast.Filecoin, ask porcelain.Ask, data files.File) (cid.Cid, *storagedeal.Response, error) { 19 | return ImportAndStoreWithDuration(ctx, client, ask, 10, data) 20 | } 21 | 22 | // ImportAndStoreWithDuration imports the `data` to the `client`, and proposes a storage 23 | // deal using the provided `ask`, returning the cid of the import and the 24 | // created deal, using the provided duration.: 25 | func ImportAndStoreWithDuration(ctx context.Context, client *fast.Filecoin, ask porcelain.Ask, duration uint64, data files.File) (cid.Cid, *storagedeal.Response, error) { 26 | // Client neeeds to import the data 27 | dcid, err := client.ClientImport(ctx, data) 28 | if err != nil { 29 | return cid.Undef, nil, err 30 | } 31 | 32 | // Client makes a deal 33 | deal, err := client.ClientProposeStorageDeal(ctx, dcid, ask.Miner, ask.ID, duration) 34 | if err != nil { 35 | return cid.Undef, nil, err 36 | } 37 | 38 | return dcid, deal, nil 39 | } 40 | -------------------------------------------------------------------------------- /tools/fast/series/init_and_start.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/tools/fast" 7 | ) 8 | 9 | // InitAndStart is a quick way to run Init and Start for a filecoin process. A variadic set of functions 10 | // can be passed to run between init and the start of the daemon to make configuration changes. 11 | func InitAndStart(ctx context.Context, node *fast.Filecoin, fns ...func(context.Context, *fast.Filecoin) error) error { 12 | if _, err := node.InitDaemon(ctx); err != nil { 13 | return err 14 | } 15 | 16 | for _, fn := range fns { 17 | if err := fn(ctx, node); err != nil { 18 | return err 19 | } 20 | } 21 | 22 | if _, err := node.StartDaemon(ctx, true); err != nil { 23 | return err 24 | } 25 | 26 | return nil 27 | } 28 | -------------------------------------------------------------------------------- /tools/fast/series/send_filecoin_defaults.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/address" 7 | "github.com/filecoin-project/go-filecoin/tools/fast" 8 | ) 9 | 10 | // SendFilecoinDefaults sends the `value` amount of fil from the default wallet 11 | // address of the `from` node to the `to` node's default wallet, and waits for the 12 | // message to be received by the `to` node. 13 | func SendFilecoinDefaults(ctx context.Context, from, to *fast.Filecoin, value int) error { 14 | var toAddr address.Address 15 | if err := to.ConfigGet(ctx, "wallet.defaultAddress", &toAddr); err != nil { 16 | return err 17 | } 18 | 19 | mcid, err := SendFilecoinFromDefault(ctx, from, toAddr, value) 20 | if err != nil { 21 | return err 22 | } 23 | 24 | if _, err := to.MessageWait(ctx, mcid); err != nil { 25 | return err 26 | } 27 | 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /tools/fast/series/send_filecoin_from_default.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | "math/big" 6 | 7 | "github.com/ipfs/go-cid" 8 | 9 | "github.com/filecoin-project/go-filecoin/address" 10 | "github.com/filecoin-project/go-filecoin/tools/fast" 11 | ) 12 | 13 | // SendFilecoinFromDefault will send the `value` of FIL from the default wallet 14 | // address, per the config of the `node`, to the provided address `addr` and 15 | // wait for the message to showup on chain. 16 | // The waiting node is the sender, this does not guarantee that the message has 17 | // been received by the targeted node of addr. 18 | func SendFilecoinFromDefault(ctx context.Context, node *fast.Filecoin, addr address.Address, value int) (cid.Cid, error) { 19 | var walletAddr address.Address 20 | if err := node.ConfigGet(ctx, "wallet.defaultAddress", &walletAddr); err != nil { 21 | return cid.Undef, err 22 | } 23 | 24 | mcid, err := node.MessageSend(ctx, addr, "", fast.AOValue(value), fast.AOFromAddr(walletAddr), fast.AOPrice(big.NewFloat(1.0)), fast.AOLimit(300)) 25 | if err != nil { 26 | return cid.Undef, err 27 | } 28 | 29 | CtxMiningOnce(ctx) 30 | 31 | if _, err := node.MessageWait(ctx, mcid); err != nil { 32 | return cid.Undef, err 33 | } 34 | 35 | return mcid, nil 36 | } 37 | -------------------------------------------------------------------------------- /tools/fast/series/set_price_ask.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "math/big" 8 | 9 | "github.com/filecoin-project/go-filecoin/abi" 10 | "github.com/filecoin-project/go-filecoin/porcelain" 11 | "github.com/filecoin-project/go-filecoin/tools/fast" 12 | ) 13 | 14 | // SetPriceGetAsk issues a `set-price` and tries, to the best it can, return the 15 | // created ask. This series will run until it finds an ask, or the context is 16 | // canceled. 17 | func SetPriceGetAsk(ctx context.Context, miner *fast.Filecoin, price *big.Float, expiry *big.Int) (porcelain.Ask, error) { 18 | // Set a price 19 | pinfo, err := miner.MinerSetPrice(ctx, price, expiry, fast.AOPrice(big.NewFloat(1.0)), fast.AOLimit(300)) 20 | if err != nil { 21 | return porcelain.Ask{}, err 22 | } 23 | 24 | response, err := miner.MessageWait(ctx, pinfo.AddAskCid) 25 | if err != nil { 26 | return porcelain.Ask{}, err 27 | } 28 | 29 | bbs := response.Receipt.Return[0] 30 | value, err := abi.Deserialize(bbs, abi.Integer) 31 | if err != nil { 32 | return porcelain.Ask{}, err 33 | } 34 | 35 | val, ok := value.Val.(*big.Int) 36 | if !ok { 37 | return porcelain.Ask{}, fmt.Errorf("could not cast askid") 38 | } 39 | 40 | var ask porcelain.Ask 41 | dec, err := miner.ClientListAsks(ctx) 42 | if err != nil { 43 | return porcelain.Ask{}, err 44 | } 45 | 46 | for { 47 | err := dec.Decode(&ask) 48 | if err != nil && err != io.EOF { 49 | return porcelain.Ask{}, err 50 | } 51 | 52 | if val.Uint64() == ask.ID && ask.Miner == pinfo.MinerAddr { 53 | return ask, nil 54 | } 55 | 56 | if err == io.EOF { 57 | break 58 | } 59 | } 60 | 61 | return porcelain.Ask{}, fmt.Errorf("could not find ask") 62 | } 63 | -------------------------------------------------------------------------------- /tools/fast/series/setup_genesis_node.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | "math/big" 6 | 7 | "github.com/ipfs/go-ipfs-files" 8 | 9 | "github.com/filecoin-project/go-filecoin/address" 10 | "github.com/filecoin-project/go-filecoin/tools/fast" 11 | ) 12 | 13 | // SetupGenesisNode will initialize, start, configure, and issue the 14 | // "start mining" command to the filecoin process `node`. Process `node` will 15 | // be configured with miner `minerAddress`, and import the address of the miner 16 | // `minerOwner`. Lastly the process `node` will start mining. 17 | func SetupGenesisNode(ctx context.Context, node *fast.Filecoin, minerAddress address.Address, minerOwner files.File) error { 18 | if _, err := node.InitDaemon(ctx); err != nil { 19 | return err 20 | } 21 | 22 | if _, err := node.StartDaemon(ctx, true); err != nil { 23 | return err 24 | } 25 | 26 | if err := node.ConfigSet(ctx, "mining.minerAddress", minerAddress.String()); err != nil { 27 | return err 28 | } 29 | 30 | wallet, err := node.WalletImport(ctx, minerOwner) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | if err := node.ConfigSet(ctx, "wallet.defaultAddress", wallet[0].String()); err != nil { 36 | return err 37 | } 38 | 39 | _, err = node.MinerUpdatePeerid(ctx, minerAddress, node.PeerID, fast.AOFromAddr(wallet[0]), fast.AOPrice(big.NewFloat(300)), fast.AOLimit(300)) 40 | 41 | return err 42 | } 43 | -------------------------------------------------------------------------------- /tools/fast/series/wait_for_block_height.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/tools/fast" 7 | "github.com/filecoin-project/go-filecoin/types" 8 | ) 9 | 10 | // WaitForBlockHeight will inspect the chain head and wait till the height is equal to or 11 | // greater than the provide height `bh` 12 | func WaitForBlockHeight(ctx context.Context, client *fast.Filecoin, bh *types.BlockHeight) error { 13 | for { 14 | 15 | hh, err := GetHeadBlockHeight(ctx, client) 16 | if err != nil { 17 | return err 18 | } 19 | 20 | if hh.GreaterEqual(bh) { 21 | break 22 | } 23 | 24 | <-CtxSleepDelay(ctx) 25 | } 26 | 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /tools/fast/series/wait_for_deal_state.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/filecoin-project/go-filecoin/protocol/storage/storagedeal" 7 | "github.com/filecoin-project/go-filecoin/tools/fast" 8 | ) 9 | 10 | // WaitForDealState will query the storage deal until its state matches the 11 | // passed in `state`, or the context is canceled. 12 | func WaitForDealState(ctx context.Context, client *fast.Filecoin, deal *storagedeal.Response, state storagedeal.State) (*storagedeal.Response, error) { 13 | for { 14 | // Client waits around for the deal to be sealed 15 | dr, err := client.ClientQueryStorageDeal(ctx, deal.ProposalCid) 16 | if err != nil { 17 | return nil, err 18 | } 19 | 20 | if dr.State == state { 21 | return dr, nil 22 | } 23 | 24 | <-CtxSleepDelay(ctx) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tools/fast/series/with_wallet.go: -------------------------------------------------------------------------------- 1 | package series 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | "github.com/filecoin-project/go-filecoin/address" 8 | "github.com/filecoin-project/go-filecoin/tools/fast" 9 | ) 10 | 11 | // ErrWithWalletRestoreFailed is returned if the original address could not be restored. 12 | var ErrWithWalletRestoreFailed = errors.New("failed to restore default wallet after WithWallet exited") 13 | 14 | // WithWallet can be used to temporarlly change the default wallet address of 15 | // the node to sessionWallet for all FAST actions executed inside of sessionFn. 16 | // 17 | // WithWallet should be used when you want to temporarally change the default 18 | // wallet address of the node. 19 | // 20 | // Error ErrWithWalletRestoreFailed will be returned if the original address 21 | // could not be restored. 22 | func WithWallet(ctx context.Context, fc *fast.Filecoin, sessionWallet address.Address, sessionFn func(*fast.Filecoin) error) (err error) { 23 | var beforeAddress address.Address 24 | if err = fc.ConfigGet(ctx, "wallet.defaultAddress", &beforeAddress); err != nil { 25 | return 26 | } 27 | 28 | if err = fc.ConfigSet(ctx, "wallet.defaultAddress", sessionWallet); err != nil { 29 | return 30 | } 31 | 32 | defer func() { 33 | err = fc.ConfigSet(ctx, "wallet.defaultAddress", beforeAddress) 34 | if err != nil { 35 | err = ErrWithWalletRestoreFailed 36 | } 37 | }() 38 | 39 | return sessionFn(fc) 40 | } 41 | -------------------------------------------------------------------------------- /tools/genesis-file-server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "net/http" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | port := flag.Int("port", 0, "port over which to serve genesis file via HTTP") 12 | genesisFilePath := flag.String("genesis-file-path", "", "full path to the genesis file to be served") 13 | flag.Parse() 14 | 15 | if len(*genesisFilePath) == 0 { 16 | fmt.Println("Please specify a genesis to serve") 17 | os.Exit(1) 18 | } 19 | 20 | ServeGenesisFileAtPort(*genesisFilePath, *port) 21 | } 22 | 23 | // ServeGenesisFileAtPort will serve the genesis.car file via HTTP at the given port for download 24 | func ServeGenesisFileAtPort(genesisFilePath string, port int) { 25 | http.HandleFunc("/genesis.car", func(w http.ResponseWriter, r *http.Request) { 26 | w.Header().Set("Content-Type", "application/octet-stream") 27 | http.ServeFile(w, r, genesisFilePath) 28 | }) 29 | panic(http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) 30 | } 31 | -------------------------------------------------------------------------------- /tools/iptb-plugins/Makefile: -------------------------------------------------------------------------------- 1 | IPTB_ROOT ?= $(HOME)/testbed 2 | 3 | all: filecoin install 4 | 5 | install: 6 | mkdir -p $(IPTB_ROOT)/plugins 7 | cp filecoin/*.so $(IPTB_ROOT)/plugins 8 | 9 | filecoin: 10 | make -C filecoin all 11 | 12 | clean: 13 | rm *.so 14 | 15 | .PHONY: all filecoin clean 16 | -------------------------------------------------------------------------------- /tools/iptb-plugins/filecoin/Makefile: -------------------------------------------------------------------------------- 1 | export GO111MODULE=on 2 | 3 | all: filecoinlocal filecoindocker 4 | 5 | filecoinlocal: 6 | (cd local/localfilecoin; go build -buildmode=plugin -o ../../localfilecoin.so) 7 | CLEAN += localfilecoin.so 8 | 9 | filecoindocker: 10 | (cd docker/dockerfilecoin; go build -buildmode=plugin -o ../../dockerfilecoin.so) 11 | CLEAN += dockerfilecoin.so 12 | 13 | .PHONY: all filecoinlocal filecoindocker 14 | -------------------------------------------------------------------------------- /tools/iptb-plugins/filecoin/docker/dockerfilecoin/plugin.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | plugin "github.com/filecoin-project/go-filecoin/tools/iptb-plugins/filecoin/docker" 5 | ) 6 | 7 | var PluginName = plugin.PluginName // nolint: golint, staticcheck, deadcode, unused 8 | var NewNode = plugin.NewNode // nolint: golint, staticcheck, deadcode, unused 9 | -------------------------------------------------------------------------------- /tools/iptb-plugins/filecoin/docker/iptb_metrics.go: -------------------------------------------------------------------------------- 1 | package pluginlocalfilecoin 2 | 3 | import ( 4 | "context" 5 | "io" 6 | 7 | "github.com/docker/docker/api/types" 8 | ) 9 | 10 | // Events not implemented 11 | func (l *Dockerfilecoin) Events() (io.ReadCloser, error) { 12 | panic("Not Implemented") 13 | } 14 | 15 | // StderrReader provides an io.ReadCloser to the running daemons stderr 16 | func (l *Dockerfilecoin) StderrReader() (io.ReadCloser, error) { 17 | cli, err := l.GetClient() 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | options := types.ContainerLogsOptions{ 23 | ShowStdout: false, 24 | ShowStderr: true, 25 | Follow: true, 26 | } 27 | 28 | return cli.ContainerLogs(context.Background(), l.ID, options) 29 | } 30 | 31 | // StdoutReader provides an io.ReadCloser to the running daemons stdout 32 | func (l *Dockerfilecoin) StdoutReader() (io.ReadCloser, error) { 33 | cli, err := l.GetClient() 34 | if err != nil { 35 | return nil, err 36 | } 37 | 38 | options := types.ContainerLogsOptions{ 39 | ShowStdout: true, 40 | ShowStderr: false, 41 | Follow: true, 42 | } 43 | 44 | return cli.ContainerLogs(context.Background(), l.ID, options) 45 | } 46 | 47 | // Heartbeat not implemented 48 | func (l *Dockerfilecoin) Heartbeat() (map[string]string, error) { 49 | panic("Not Implemented") 50 | } 51 | 52 | // Metric not implemented 53 | func (l *Dockerfilecoin) Metric(key string) (string, error) { 54 | panic("Not Implemented") 55 | } 56 | 57 | // GetMetricList not implemented 58 | func (l *Dockerfilecoin) GetMetricList() []string { 59 | panic("Not Implemented") 60 | } 61 | 62 | // GetMetricDesc not implemented 63 | func (l *Dockerfilecoin) GetMetricDesc(key string) (string, error) { 64 | panic("Not Implemented") 65 | } 66 | -------------------------------------------------------------------------------- /tools/iptb-plugins/filecoin/local/copy_file.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package pluginlocalfilecoin 4 | 5 | import ( 6 | "io" 7 | "os" 8 | ) 9 | 10 | // https://stackoverflow.com/a/21061062 11 | func copyFileContents(src, dst string) (err error) { 12 | in, err := os.Open(src) 13 | if err != nil { 14 | return 15 | } 16 | 17 | defer in.Close() // nolint: errcheck 18 | out, err := os.Create(dst) 19 | if err != nil { 20 | return 21 | } 22 | 23 | defer func() { 24 | cerr := out.Close() 25 | if err == nil { 26 | err = cerr 27 | } 28 | }() 29 | 30 | if _, err = io.Copy(out, in); err != nil { 31 | return 32 | } 33 | 34 | err = out.Sync() 35 | return 36 | } 37 | -------------------------------------------------------------------------------- /tools/iptb-plugins/filecoin/local/copy_file_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package pluginlocalfilecoin 4 | 5 | import ( 6 | "os/exec" 7 | ) 8 | 9 | // We can't copy the bits in go due to the following bug 10 | // https://github.com/golang/go/issues/22315 11 | func copyFileContents(src, dst string) (err error) { 12 | cmd := exec.Command("cp", src, dst) 13 | if err := cmd.Start(); err != nil { 14 | return err 15 | } 16 | 17 | return cmd.Wait() 18 | } 19 | -------------------------------------------------------------------------------- /tools/iptb-plugins/filecoin/local/iptb_metrics.go: -------------------------------------------------------------------------------- 1 | package pluginlocalfilecoin 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | // Events not implemented 8 | func (l *Localfilecoin) Events() (io.ReadCloser, error) { 9 | panic("Not Implemented") 10 | } 11 | 12 | // StderrReader provides an io.ReadCloser to the running daemons stderr 13 | func (l *Localfilecoin) StderrReader() (io.ReadCloser, error) { 14 | return l.readerFor("daemon.stderr") 15 | } 16 | 17 | // StdoutReader provides an io.ReadCloser to the running daemons stdout 18 | func (l *Localfilecoin) StdoutReader() (io.ReadCloser, error) { 19 | return l.readerFor("daemon.stdout") 20 | } 21 | 22 | // Heartbeat not implemented 23 | func (l *Localfilecoin) Heartbeat() (map[string]string, error) { 24 | panic("Not Implemented") 25 | } 26 | 27 | // Metric not implemented 28 | func (l *Localfilecoin) Metric(key string) (string, error) { 29 | panic("Not Implemented") 30 | } 31 | 32 | // GetMetricList not implemented 33 | func (l *Localfilecoin) GetMetricList() []string { 34 | panic("Not Implemented") 35 | } 36 | 37 | // GetMetricDesc not implemented 38 | func (l *Localfilecoin) GetMetricDesc(key string) (string, error) { 39 | panic("Not Implemented") 40 | } 41 | -------------------------------------------------------------------------------- /tools/iptb-plugins/filecoin/local/localfilecoin/plugin.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | plugin "github.com/filecoin-project/go-filecoin/tools/iptb-plugins/filecoin/local" 5 | ) 6 | 7 | var PluginName = plugin.PluginName // nolint: golint, staticcheck, deadcode, unused 8 | var NewNode = plugin.NewNode // nolint: golint, staticcheck, deadcode, unused 9 | -------------------------------------------------------------------------------- /tools/iptb-plugins/filecoin/mock/mockfilecoin_metrics.go: -------------------------------------------------------------------------------- 1 | package pluginmockfilecoin 2 | 3 | import ( 4 | "io" 5 | "io/ioutil" 6 | ) 7 | 8 | // StderrReader returns an io.ReadCloser that represents daemon stderr 9 | func (m *Mockfilecoin) StderrReader() (io.ReadCloser, error) { 10 | return ioutil.NopCloser(&m.stderr), nil 11 | } 12 | 13 | // StdoutReader returns an io.ReadCloser that represents daemon stdout 14 | func (m *Mockfilecoin) StdoutReader() (io.ReadCloser, error) { 15 | return ioutil.NopCloser(&m.stdout), nil 16 | } 17 | -------------------------------------------------------------------------------- /tools/migration/README.md: -------------------------------------------------------------------------------- 1 | # IMPORTANT 2 | 3 | **DO NOT REGENERATE** test fixtures associated with a migration, using go-filecoin code that is later than the intended "oldVersion" associated with the migration. 4 | 5 | This will not only invalidate the tests, but users will be unable to run migrations on 6 | their repo, because the migration code becomes polluted with behaviors past its original 7 | intended versions. The migration will likely become completely unable to read their repo. 8 | 9 | If your changes have broken migration tests, then one of the following scenarios may apply: 10 | 11 | 1. A migration has already been created and merged for the upcoming release, and you are are making more breaking changes to the repo. In this case, you will need to: 12 | 13 | * write your own migration for your changes and backport the old code to the other one, 14 |
OR 15 | * include your changes in the other migration. 16 | 2. The migration is recent but applies to a previous release. In this case you need to write a new migration and backport the old code. 17 | 3. The previous migration version is enough versions behind that no nodes should even be running it by now. Consider invalidating the broken migration. -------------------------------------------------------------------------------- /tools/migration/internal/default_migrations_provider.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | // DefaultMigrationsProvider provides a list of migrations available for migrating 4 | // in production. 5 | // To add a migration: 6 | // 1. add a migration folder in tools/migration/migrations like repo-- 7 | // 2. put the migration code in the folder in its own package 8 | // 2. add the new migration package to the imports above 9 | // 3. instantiate and append it to the list of migrations returned by DefaultMigrationsProvider 10 | // 11 | // See runner_test for examples. 12 | 13 | import ( 14 | migration12 "github.com/filecoin-project/go-filecoin/tools/migration/migrations/repo-1-2" 15 | ) 16 | 17 | // DefaultMigrationsProvider is the migrations provider dependency used in production. 18 | // You may provide a test version when needed. Please see runner_test.go for more information. 19 | func DefaultMigrationsProvider() []Migration { 20 | return []Migration{ 21 | &migration12.MetadataFormatJSONtoCBOR{}, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tools/migration/internal/logger.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "io" 5 | "log" 6 | "os" 7 | ) 8 | 9 | // Logger logs migration events to disk and, if initialized with verbose, 10 | // stdout too. 11 | type Logger struct { 12 | closer io.WriteCloser 13 | logger *log.Logger 14 | } 15 | 16 | // NewLogger creates a new Logger. All log writes go to f, the logging file. 17 | // If the verbose flag is true all log writes also go to stdout. 18 | func NewLogger(wc io.WriteCloser, verbose bool) *Logger { 19 | // by default just write to file 20 | var w io.Writer 21 | w = wc 22 | if verbose { 23 | w = io.MultiWriter(wc, os.Stdout) 24 | } 25 | return &Logger{ 26 | closer: wc, 27 | logger: log.New(w, "[Filecoin Migration] ", log.LstdFlags), 28 | } 29 | } 30 | 31 | // Error logs an error to the logging output. 32 | func (l *Logger) Error(err error) { 33 | if err == nil { 34 | return 35 | } 36 | l.logger.Printf("ERROR: %s", err.Error()) 37 | } 38 | 39 | // Print logs a string to the logging output. 40 | func (l *Logger) Print(msg string) { 41 | l.logger.Print(msg) 42 | } 43 | 44 | // Printf logs and formats a string to the logging output. 45 | func (l *Logger) Printf(format string, v ...interface{}) { 46 | l.logger.Printf(format, v...) 47 | } 48 | 49 | // Close closes the logfile backing the Logger. 50 | func (l *Logger) Close() error { 51 | return l.closer.Close() 52 | } 53 | -------------------------------------------------------------------------------- /tools/migration/internal/runner_buildonly_test.go: -------------------------------------------------------------------------------- 1 | package internal_test 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/filecoin-project/go-filecoin/repo" 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | 11 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 12 | . "github.com/filecoin-project/go-filecoin/tools/migration/internal" 13 | ) 14 | 15 | func TestMigrationRunner_RunBuildonly(t *testing.T) { 16 | tf.UnitTest(t) 17 | 18 | container, repoSymLink := RequireInitRepo(t, 0) 19 | oldRepoPath := repo.RequireReadLink(t, repoSymLink) 20 | defer repo.RequireRemoveAll(t, container) 21 | 22 | t.Run("clones repo, updates version, does not install", func(t *testing.T) { 23 | dummyLogFile, dummyLogPath := repo.RequireOpenTempFile(t, "logfile") 24 | defer repo.RequireRemoveAll(t, dummyLogPath) 25 | logger := NewLogger(dummyLogFile, false) 26 | runner, err := NewMigrationRunner(logger, "buildonly", repoSymLink, "") 27 | require.NoError(t, err) 28 | runner.MigrationsProvider = testProviderPasses 29 | 30 | runResult := runner.Run() 31 | assert.NoError(t, runResult.Err) 32 | 33 | stat, err := os.Stat(runResult.NewRepoPath) 34 | require.NoError(t, err) 35 | assert.True(t, stat.IsDir()) 36 | 37 | AssertBumpedVersion(t, runResult.NewRepoPath, repoSymLink, 0) 38 | assert.Equal(t, uint(1), runResult.NewVersion) 39 | AssertLinked(t, oldRepoPath, repoSymLink) 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /tools/migration/main_whitebox_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "testing" 5 | 6 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 7 | ast "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestMigrationRunner_findOpt(t *testing.T) { 11 | tf.UnitTest(t) 12 | assert := ast.New(t) 13 | args := []string{"newRepo=/tmp/somedir", "verbose"} 14 | 15 | t.Run("returns the value+true for an option, if given", func(t *testing.T) { 16 | val, found := findOpt("newRepo", args) 17 | assert.True(found) 18 | assert.Equal("/tmp/somedir", val) 19 | }) 20 | 21 | t.Run("returns empty string + true for option with no value set", func(t *testing.T) { 22 | val, found := findOpt("verbose", args) 23 | assert.True(found) 24 | assert.Equal("", val) 25 | }) 26 | 27 | t.Run("returns empty string + false if option is not found", func(t *testing.T) { 28 | val, found := findOpt("nuffin", args) 29 | assert.False(found) 30 | assert.Equal("", val) 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /tools/migration/migrations/repo-1-2/fixtures/repo-1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FirmaChain/go-filecoin/4fcb713a209be0efac91da709cabbcfe89ceee7c/tools/migration/migrations/repo-1-2/fixtures/repo-1.tgz -------------------------------------------------------------------------------- /types/bytes_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "bytes" 5 | cbor "github.com/ipfs/go-ipld-cbor" 6 | "testing" 7 | 8 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestRoundtrip(t *testing.T) { 13 | tf.UnitTest(t) 14 | 15 | cases := [][]byte{nil, {}, []byte("bytes")} 16 | for _, c := range cases { 17 | b, err := cbor.WrapObject(c, DefaultHashFunction, -1) 18 | assert.NoError(t, err) 19 | var out []byte 20 | err = cbor.DecodeInto(b.RawData(), &out) 21 | assert.NoError(t, err) 22 | switch { 23 | case c == nil: 24 | assert.Nil(t, out) 25 | default: 26 | assert.True(t, bytes.Equal(c, out)) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /types/chain_info.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/libp2p/go-libp2p-core/peer" 7 | ) 8 | 9 | // ChainInfo is used to track metadata about a peer and its chain. 10 | type ChainInfo struct { 11 | Peer peer.ID 12 | Head TipSetKey 13 | Height uint64 14 | } 15 | 16 | // NewChainInfo creates a chain info from a peer id a head tipset key and a 17 | // chain height. 18 | func NewChainInfo(peer peer.ID, head TipSetKey, height uint64) *ChainInfo { 19 | return &ChainInfo{ 20 | Peer: peer, 21 | Head: head, 22 | Height: height, 23 | } 24 | } 25 | 26 | // Returns a human-readable string representation of a chain info 27 | func (i *ChainInfo) String() string { 28 | return fmt.Sprintf("{peer=%s height=%d head=%s}", i.Peer, i.Height, i.Head) 29 | } 30 | 31 | // CISlice is for sorting chain infos 32 | type CISlice []*ChainInfo 33 | 34 | // Len returns the number of chain infos in the slice. 35 | func (cis CISlice) Len() int { return len(cis) } 36 | 37 | // Swap swaps chain infos. 38 | func (cis CISlice) Swap(i, j int) { cis[i], cis[j] = cis[j], cis[i] } 39 | 40 | // Less compares chain infos on peer ID. There should only ever be one chain 41 | // info per peer in a CISlice. 42 | func (cis CISlice) Less(i, j int) bool { return string(cis[i].Peer) < string(cis[j].Peer) } 43 | -------------------------------------------------------------------------------- /types/commitments.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | cbor "github.com/ipfs/go-ipld-cbor" 5 | ) 6 | 7 | func init() { 8 | cbor.RegisterCborType(Commitments{}) 9 | } 10 | 11 | // Commitments is a struct containing the replica and data commitments produced 12 | // when sealing a sector. 13 | type Commitments struct { 14 | CommD CommD 15 | CommR CommR 16 | CommRStar CommRStar 17 | } 18 | 19 | // PoStChallengeSeedBytesLen is the number of bytes in the Proof of SpaceTime challenge seed. 20 | const PoStChallengeSeedBytesLen uint = 32 21 | 22 | // CommitmentBytesLen is the number of bytes in a CommR, CommD, CommP, and CommRStar. 23 | const CommitmentBytesLen uint = 32 24 | 25 | // PoStChallengeSeed is an input to the proof-of-spacetime generation and verification methods. 26 | type PoStChallengeSeed [PoStChallengeSeedBytesLen]byte 27 | 28 | // CommR is the merkle root of the replicated data. It is an output of the 29 | // sector sealing (PoRep) process. 30 | type CommR [CommitmentBytesLen]byte 31 | 32 | // CommD is the merkle root of the original user data. It is an output of the 33 | // sector sealing (PoRep) process. 34 | type CommD [CommitmentBytesLen]byte 35 | 36 | // CommP is the merkle root of a piece of data included within the original user data. It is 37 | // generated by the client, and the miner must generated a piece inclusion proof from CommP 38 | // to CommD. 39 | type CommP [CommitmentBytesLen]byte 40 | 41 | // CommRStar is a hash of intermediate layers. It is an output of the sector 42 | // sealing (PoRep) process. 43 | type CommRStar [CommitmentBytesLen]byte 44 | -------------------------------------------------------------------------------- /types/fault_set.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "fmt" 5 | 6 | cbor "github.com/ipfs/go-ipld-cbor" 7 | ) 8 | 9 | func init() { 10 | cbor.RegisterCborType(FaultSet{}) 11 | } 12 | 13 | // FaultSet indicates sectors that have failed PoSt during a proving period 14 | // 15 | // https://github.com/filecoin-project/specs/blob/master/data-structures.md#faultset 16 | type FaultSet struct { 17 | // Offset is the offset from the start of the proving period, currently unused 18 | Offset uint64 `json:"offset,omitempty" refmt:"idx"` 19 | 20 | // SectorIds are the faulted sectors 21 | SectorIds IntSet `json:"sectorIds" refmt:"ids"` 22 | } 23 | 24 | // NewFaultSet constructs a FaultSet from a slice of sector ids that have faulted 25 | func NewFaultSet(sectorIds []uint64) FaultSet { 26 | return FaultSet{SectorIds: NewIntSet(sectorIds...)} 27 | } 28 | 29 | // EmptyFaultSet constructs an empty FaultSet as a convenience 30 | func EmptyFaultSet() FaultSet { 31 | return FaultSet{SectorIds: EmptyIntSet()} 32 | } 33 | 34 | // String returns a printable representation of the FaultSet 35 | func (fs FaultSet) String() string { 36 | return fmt.Sprintf("%d / %s", fs.Offset, fs.SectorIds.String()) 37 | } 38 | -------------------------------------------------------------------------------- /types/fault_set_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 7 | cbor "github.com/ipfs/go-ipld-cbor" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestFaultSetCborMarshaling(t *testing.T) { 13 | tf.UnitTest(t) 14 | 15 | t.Run("encode/decode symmetry", func(t *testing.T) { 16 | faultSet := NewFaultSet([]uint64{4096, 1, 2, 3, 8192}) 17 | decoded := NewFaultSet([]uint64{}) 18 | 19 | out, err := cbor.DumpObject(faultSet) 20 | assert.NoError(t, err) 21 | 22 | err = cbor.DecodeInto(out, &decoded) 23 | assert.NoError(t, err) 24 | 25 | assert.Equal(t, faultSet.SectorIds.Values(), decoded.SectorIds.Values()) 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /types/full_block.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // FullBlock carries a block header and the message and receipt collections 4 | // referenced from the header. 5 | type FullBlock struct { 6 | Header *Block 7 | Messages []*SignedMessage 8 | Receipts []*MessageReceipt 9 | } 10 | 11 | // NewFullBlock constructs a new full block. 12 | func NewFullBlock(header *Block, msgs []*SignedMessage, rcpts []*MessageReceipt) *FullBlock { 13 | return &FullBlock{ 14 | Header: header, 15 | Messages: msgs, 16 | Receipts: rcpts, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /types/helpers.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | const ( 4 | // SECP256K1 is a curve used to compute private keys 5 | SECP256K1 = "secp256k1" 6 | ) 7 | -------------------------------------------------------------------------------- /types/keyinfo.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "bytes" 5 | 6 | cbor "github.com/ipfs/go-ipld-cbor" 7 | 8 | "github.com/filecoin-project/go-filecoin/address" 9 | "github.com/filecoin-project/go-filecoin/crypto" 10 | ) 11 | 12 | func init() { 13 | cbor.RegisterCborType(KeyInfo{}) 14 | } 15 | 16 | // KeyInfo is a key and its type used for signing. 17 | type KeyInfo struct { 18 | // Private key. 19 | PrivateKey []byte `json:"privateKey"` 20 | // Curve used to generate private key. 21 | Curve string `json:"curve"` 22 | } 23 | 24 | // Unmarshal decodes raw cbor bytes into KeyInfo. 25 | func (ki *KeyInfo) Unmarshal(b []byte) error { 26 | return cbor.DecodeInto(b, ki) 27 | } 28 | 29 | // Marshal KeyInfo into bytes. 30 | func (ki *KeyInfo) Marshal() ([]byte, error) { 31 | return cbor.DumpObject(ki) 32 | } 33 | 34 | // Key returns the private key of KeyInfo 35 | func (ki *KeyInfo) Key() []byte { 36 | return ki.PrivateKey 37 | } 38 | 39 | // Type returns the type of curve used to generate the private key 40 | func (ki *KeyInfo) Type() string { 41 | return ki.Curve 42 | } 43 | 44 | // Equals returns true if the KeyInfo is equal to other. 45 | func (ki *KeyInfo) Equals(other *KeyInfo) bool { 46 | if ki == nil && other == nil { 47 | return true 48 | } 49 | if ki == nil || other == nil { 50 | return false 51 | } 52 | if ki.Curve != other.Curve { 53 | return false 54 | } 55 | 56 | return bytes.Equal(ki.PrivateKey, other.PrivateKey) 57 | } 58 | 59 | // Address returns the address for this keyinfo 60 | func (ki *KeyInfo) Address() (address.Address, error) { 61 | // TODO: Use the address type we are running on from the config. 62 | return address.NewSecp256k1Address(ki.PublicKey()) 63 | } 64 | 65 | // PublicKey returns the public key part as uncompressed bytes. 66 | func (ki *KeyInfo) PublicKey() []byte { 67 | return crypto.PublicKey(ki.PrivateKey) 68 | } 69 | -------------------------------------------------------------------------------- /types/keyinfo_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | "github.com/filecoin-project/go-filecoin/crypto" 9 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 10 | ) 11 | 12 | func TestKeyInfoMarshal(t *testing.T) { 13 | tf.UnitTest(t) 14 | 15 | testKey, err := crypto.GenerateKey() 16 | assert.NoError(t, err) 17 | testType := "test_key_type" 18 | ki := &KeyInfo{ 19 | PrivateKey: testKey, 20 | Curve: testType, 21 | } 22 | 23 | marshaled, err := ki.Marshal() 24 | assert.NoError(t, err) 25 | 26 | kiBack := &KeyInfo{} 27 | err = kiBack.Unmarshal(marshaled) 28 | assert.NoError(t, err) 29 | 30 | assert.Equal(t, ki.Key(), kiBack.Key()) 31 | assert.Equal(t, ki.Type(), kiBack.Type()) 32 | assert.True(t, ki.Equals(kiBack)) 33 | } 34 | -------------------------------------------------------------------------------- /types/message_receipt.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | cbor "github.com/ipfs/go-ipld-cbor" 8 | ) 9 | 10 | func init() { 11 | cbor.RegisterCborType(MessageReceipt{}) 12 | } 13 | 14 | // MessageReceipt represents the result of sending a message. 15 | type MessageReceipt struct { 16 | // `0` is success, anything else is an error code in unix style. 17 | ExitCode uint8 `json:"exitCode"` 18 | 19 | // Return contains the return values, if any, from processing a message. 20 | // This can be non-empty even in the case of error (e.g., to provide 21 | // programmatically readable detail about errors). 22 | Return [][]byte `json:"return"` 23 | 24 | // GasAttoFIL Charge is the actual amount of FIL transferred from the sender to the miner for processing the message 25 | GasAttoFIL AttoFIL `json:"gasAttoFIL"` 26 | } 27 | 28 | func (mr *MessageReceipt) String() string { 29 | errStr := "(error encoding MessageReceipt)" 30 | 31 | js, err := json.MarshalIndent(mr, "", " ") 32 | if err != nil { 33 | return errStr 34 | } 35 | return fmt.Sprintf("MessageReceipt: %s", string(js)) 36 | } 37 | -------------------------------------------------------------------------------- /types/message_receipt_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | cbor "github.com/ipfs/go-ipld-cbor" 7 | 8 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestMessageReceiptMarshal(t *testing.T) { 13 | tf.UnitTest(t) 14 | 15 | cases := []MessageReceipt{ 16 | { 17 | ExitCode: 1, 18 | }, 19 | { 20 | ExitCode: 0, 21 | Return: [][]byte{{1, 2, 3}}, 22 | }, 23 | {}, 24 | } 25 | 26 | for _, expected := range cases { 27 | bytes, err := cbor.DumpObject(expected) 28 | assert.NoError(t, err) 29 | 30 | var actual MessageReceipt 31 | err = cbor.DecodeInto(bytes, &actual) 32 | 33 | assert.NoError(t, err) 34 | assert.Equal(t, expected.ExitCode, actual.ExitCode) 35 | assert.Equal(t, expected.Return, actual.Return) 36 | assert.True(t, expected.GasAttoFIL.Equal(actual.GasAttoFIL)) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /types/metered_message_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | 10 | "github.com/filecoin-project/go-filecoin/address" 11 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 12 | ) 13 | 14 | func TestMeteredMessageMessage(t *testing.T) { 15 | tf.UnitTest(t) 16 | 17 | addrGetter := address.NewForTestGetter() 18 | 19 | t.Run("marshal and equality", func(t *testing.T) { 20 | inner := NewMessage( 21 | addrGetter(), 22 | addrGetter(), 23 | 42, 24 | NewAttoFILFromFIL(17777), 25 | "send", 26 | []byte("foobar"), 27 | ) 28 | 29 | mmsg := NewMeteredMessage(*inner, NewAttoFILFromFIL(2), NewGasUnits(300)) 30 | 31 | // This check requests that you add a non-zero value for new fields above, 32 | // then update the field count below. 33 | require.Equal(t, 3, reflect.TypeOf(*mmsg).NumField()) 34 | 35 | marshalled, err := mmsg.Marshal() 36 | assert.NoError(t, err) 37 | 38 | msgBack := MeteredMessage{} 39 | assert.False(t, mmsg.Equals(&msgBack)) 40 | 41 | err = msgBack.Unmarshal(marshalled) 42 | assert.NoError(t, err) 43 | 44 | assert.Equal(t, mmsg.To, msgBack.To) 45 | assert.Equal(t, mmsg.From, msgBack.From) 46 | assert.Equal(t, mmsg.Value, msgBack.Value) 47 | assert.Equal(t, mmsg.Method, msgBack.Method) 48 | assert.Equal(t, mmsg.Params, msgBack.Params) 49 | assert.Equal(t, mmsg.GasPrice, msgBack.GasPrice) 50 | assert.Equal(t, mmsg.GasLimit, msgBack.GasLimit) 51 | 52 | assert.True(t, mmsg.Equals(&msgBack)) 53 | }) 54 | } 55 | -------------------------------------------------------------------------------- /types/porep_proof_partitions.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/pkg/errors" 7 | ) 8 | 9 | // PoRepProofPartitions represents the number of partitions used when creating a 10 | // PoRep proof, and impacts the size of the proof. 11 | type PoRepProofPartitions int 12 | 13 | const ( 14 | // UnknownPoRepProofPartitions is an opaque value signaling that an unknown number 15 | // of partitions were used when creating a PoRep proof in test mode. 16 | UnknownPoRepProofPartitions = PoRepProofPartitions(iota) 17 | 18 | // TwoPoRepProofPartitions indicates that two partitions were used to create a PoRep proof. 19 | TwoPoRepProofPartitions 20 | ) 21 | 22 | // Int returns an integer representing the number of PoRep partitions 23 | func (p PoRepProofPartitions) Int() int { 24 | switch p { 25 | case TwoPoRepProofPartitions: 26 | return 2 27 | default: 28 | panic(fmt.Sprintf("unexpected value %v", p)) 29 | } 30 | } 31 | 32 | // ProofLen returns an integer representing the number of bytes in a PoRep proof 33 | // created with this number of partitions. 34 | func (p PoRepProofPartitions) ProofLen() int { 35 | switch p { 36 | case TwoPoRepProofPartitions: 37 | return SinglePartitionProofLen * 2 38 | default: 39 | panic(fmt.Sprintf("unexpected value %v", p)) 40 | } 41 | } 42 | 43 | // NewPoRepProofPartitions produces the PoRepProofPartitions corresponding to 44 | // the provided integer. 45 | func NewPoRepProofPartitions(numPartitions int) (PoRepProofPartitions, error) { 46 | switch numPartitions { 47 | case 2: 48 | return TwoPoRepProofPartitions, nil 49 | default: 50 | return UnknownPoRepProofPartitions, errors.Errorf("unexpected value %v", numPartitions) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /types/post_proof_partitions.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "fmt" 5 | "github.com/pkg/errors" 6 | ) 7 | 8 | // PoStProofPartitions represents the number of partitions used when creating a 9 | // PoSt proof, and impacts the size of the proof. 10 | type PoStProofPartitions int 11 | 12 | const ( 13 | // UnknownPoStProofPartitions is an opaque value signaling that an unknown number of 14 | // partitions were used when creating a PoSt proof in test mode. 15 | UnknownPoStProofPartitions = PoStProofPartitions(iota) 16 | 17 | // OnePoStProofPartition indicates that a single partition was used to create a PoSt proof. 18 | OnePoStProofPartition 19 | ) 20 | 21 | // Int returns an integer representing the number of PoSt partitions 22 | func (p PoStProofPartitions) Int() int { 23 | switch p { 24 | case OnePoStProofPartition: 25 | return 1 26 | default: 27 | panic(fmt.Sprintf("unexpected value %v", p)) 28 | } 29 | } 30 | 31 | // ProofLen returns an integer representing the number of bytes in a PoSt proof 32 | // created with this number of partitions. 33 | func (p PoStProofPartitions) ProofLen() int { 34 | switch p { 35 | case OnePoStProofPartition: 36 | return SinglePartitionProofLen 37 | default: 38 | panic(fmt.Sprintf("unexpected value %v", p)) 39 | } 40 | } 41 | 42 | // NewPoStProofPartitions produces the PoStProofPartitions corresponding to the 43 | // provided integer. 44 | func NewPoStProofPartitions(numPartitions int) (PoStProofPartitions, error) { 45 | switch numPartitions { 46 | case 1: 47 | return OnePoStProofPartition, nil 48 | default: 49 | return UnknownPoStProofPartitions, errors.Errorf("unexpected value %v", numPartitions) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /types/proofs.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | ) 6 | 7 | // SinglePartitionProofLen represents the number of bytes in a single partition 8 | // PoRep or PoSt proof. The total length of a PoSt or PoRep proof equals the 9 | // product of SinglePartitionProofLen and the number of partitions. 10 | const SinglePartitionProofLen int = 192 11 | 12 | // PoStProof is the byte representation of the Proof of SpaceTime proof 13 | type PoStProof []byte 14 | 15 | // PoRepProof is the byte representation of the Seal Proof of Replication 16 | type PoRepProof []byte 17 | 18 | // ProofPartitions returns the number of partitions used to create the PoRep 19 | // proof, or an error if the PoRep proof has an unsupported length. 20 | func (s PoRepProof) ProofPartitions() (PoRepProofPartitions, error) { 21 | n := len(s) 22 | 23 | if n%SinglePartitionProofLen != 0 { 24 | return UnknownPoRepProofPartitions, errors.Errorf("invalid PoRep proof length %d", n) 25 | } 26 | 27 | return NewPoRepProofPartitions(n / SinglePartitionProofLen) 28 | } 29 | 30 | // ProofPartitions returns the number of partitions used to create the PoSt 31 | // proof, or an error if the PoSt proof has an unsupported length. 32 | func (s PoStProof) ProofPartitions() (PoStProofPartitions, error) { 33 | n := len(s) 34 | 35 | if n%SinglePartitionProofLen != 0 { 36 | return UnknownPoStProofPartitions, errors.Errorf("invalid PoSt proof length %d", n) 37 | } 38 | 39 | return NewPoStProofPartitions(n / SinglePartitionProofLen) 40 | } 41 | -------------------------------------------------------------------------------- /types/proofs_mode.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // ProofsMode configures sealing, sector packing, PoSt generation and other 4 | // behaviors of sector_builder_ffi. Use Test mode to seal and generate PoSts 5 | // quickly over tiny sectors. Use Live when operating a real Filecoin node. 6 | type ProofsMode int 7 | 8 | const ( 9 | // UnsetProofsMode is the default 10 | UnsetProofsMode = ProofsMode(iota) 11 | // TestProofsMode changes sealing, sector packing, PoSt, etc. to be compatible with test environments 12 | TestProofsMode 13 | // LiveProofsMode changes sealing, sector packing, PoSt, etc. to be compatible with non-test environments 14 | LiveProofsMode 15 | ) 16 | -------------------------------------------------------------------------------- /types/recoverer.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // Recoverer is an interface for ecrecover 4 | type Recoverer interface { 5 | Ecrecover(data []byte, sig Signature) ([]byte, error) 6 | } 7 | -------------------------------------------------------------------------------- /types/sector_class.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // SectorClass represents the miner's chosen sector size and PoSt/seal proof 4 | // partitions. 5 | type SectorClass struct { 6 | poStProofPartitions PoStProofPartitions 7 | poRepProofPartitions PoRepProofPartitions 8 | sectorSize *BytesAmount 9 | } 10 | 11 | // NewSectorClass returns a sector class configured with the provided sector 12 | // size. Note that there must exist a published Groth parameter and verifying 13 | // key in order for the sector size to be usable. A miner configured to use a 14 | // sector size for which we have not published Groth parameters will fail to 15 | // prove their storage. 16 | func NewSectorClass(sectorSize *BytesAmount) SectorClass { 17 | return SectorClass{ 18 | poRepProofPartitions: TwoPoRepProofPartitions, 19 | poStProofPartitions: OnePoStProofPartition, 20 | sectorSize: sectorSize, 21 | } 22 | } 23 | 24 | // PoRepProofPartitions returns the sector class's PoRep proof partitions 25 | func (sc *SectorClass) PoRepProofPartitions() PoRepProofPartitions { 26 | return sc.poRepProofPartitions 27 | } 28 | 29 | // PoStProofPartitions returns the sector class's PoSt proof partitions 30 | func (sc *SectorClass) PoStProofPartitions() PoStProofPartitions { 31 | return sc.poStProofPartitions 32 | } 33 | 34 | // SectorSize returns the size of this sector class's sectors after bit-padding 35 | // has been added. Note that the amount of user bytes that will fit into a 36 | // sector is less than SectorSize due to bit-padding. 37 | func (sc *SectorClass) SectorSize() *BytesAmount { 38 | return sc.sectorSize 39 | } 40 | -------------------------------------------------------------------------------- /types/sector_size.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // OneKiBSectorSize contain 1024 bytes after sealing. These sectors are used 4 | // when the network is in TestProofsMode. 5 | var OneKiBSectorSize = NewBytesAmount(1024) 6 | 7 | // TwoHundredFiftySixMiBSectorSize contain 256MiB after sealing. These sectors 8 | // are used when the network is in LiveProofsMode. 9 | var TwoHundredFiftySixMiBSectorSize = NewBytesAmount(1 << 28) 10 | -------------------------------------------------------------------------------- /types/signature.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | logging "github.com/ipfs/go-log" 5 | 6 | "github.com/filecoin-project/go-filecoin/address" 7 | wutil "github.com/filecoin-project/go-filecoin/wallet/util" 8 | ) 9 | 10 | var log = logging.Logger("types") 11 | 12 | // Signature is the result of a cryptographic sign operation. 13 | type Signature []byte 14 | 15 | // IsValidSignature cryptographically verifies that 'sig' is the signed hash of 'data' with 16 | // the public key belonging to `addr`. 17 | func IsValidSignature(data []byte, addr address.Address, sig Signature) bool { 18 | maybePk, err := wutil.Ecrecover(data, sig) 19 | if err != nil { 20 | // Any error returned from Ecrecover means this signature is not valid. 21 | log.Infof("error in signature validation: %s", err) 22 | return false 23 | } 24 | maybeAddr, err := address.NewSecp256k1Address(maybePk) 25 | if err != nil { 26 | log.Infof("error in recovered address: %s", err) 27 | return false 28 | } 29 | return maybeAddr == addr 30 | } 31 | -------------------------------------------------------------------------------- /types/signer.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "github.com/filecoin-project/go-filecoin/address" 4 | 5 | // Signer is an interface for SignBytes 6 | type Signer interface { 7 | SignBytes(data []byte, addr address.Address) (Signature, error) 8 | } 9 | -------------------------------------------------------------------------------- /types/testing_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 9 | ) 10 | 11 | func TestCidForTestGetter(t *testing.T) { 12 | tf.UnitTest(t) 13 | 14 | newCid := NewCidForTestGetter() 15 | c1 := newCid() 16 | c2 := newCid() 17 | assert.False(t, c1.Equals(c2)) 18 | assert.False(t, c1.Equals(CidFromString(t, "somecid"))) // Just in case. 19 | } 20 | 21 | func TestNewMessageForTestGetter(t *testing.T) { 22 | tf.UnitTest(t) 23 | 24 | newMsg := NewMessageForTestGetter() 25 | m1 := newMsg() 26 | c1, _ := m1.Cid() 27 | m2 := newMsg() 28 | c2, _ := m2.Cid() 29 | assert.False(t, c1.Equals(c2)) 30 | } 31 | -------------------------------------------------------------------------------- /types/ticket.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "fmt" 5 | 6 | cbor "github.com/ipfs/go-ipld-cbor" 7 | ) 8 | 9 | func init() { 10 | cbor.RegisterCborType(Ticket{}) 11 | } 12 | 13 | // A Ticket is a marker of a tick of the blockchain's clock. It is the source 14 | // of randomness for proofs of storage and leader election. It is generated 15 | // by the miner of a block using a VRF and a VDF. 16 | type Ticket struct { 17 | // A proof output by running a VRF on the VDFResult of the parent ticket 18 | VRFProof VRFPi 19 | 20 | // Data derived by running a VDF on VRFProof 21 | VDFResult VDFY 22 | 23 | // A proof of delay during computation of VDFResult 24 | VDFProof VDFPi 25 | } 26 | 27 | // SortKey returns the canonical byte ordering of the ticket 28 | func (t Ticket) SortKey() []byte { 29 | return t.VRFProof 30 | } 31 | 32 | // String returns the string representation of the VDFResult of the ticket 33 | func (t Ticket) String() string { 34 | return fmt.Sprintf("%x", t.VDFResult) 35 | } 36 | 37 | // VRFPi is the proof output from running a VRF. 38 | type VRFPi []byte 39 | 40 | // VDFPi is proof that a VDF operation was applied on input X to get output Y. 41 | type VDFPi []byte 42 | 43 | // VDFY is the output of running a VDF operation on some input X. 44 | type VDFY []byte 45 | -------------------------------------------------------------------------------- /types/uint64.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "strconv" 5 | "strings" 6 | 7 | "github.com/filecoin-project/go-leb128" 8 | cbor "github.com/ipfs/go-ipld-cbor" 9 | "github.com/polydawn/refmt/obj/atlas" 10 | ) 11 | 12 | func init() { 13 | cbor.RegisterCborType(uint64AtlasEntry) 14 | } 15 | 16 | var uint64AtlasEntry = atlas.BuildEntry(Uint64(0)).Transform(). 17 | TransformMarshal(atlas.MakeMarshalTransformFunc( 18 | func(u Uint64) ([]byte, error) { 19 | return leb128.FromUInt64(uint64(u)), nil 20 | })). 21 | TransformUnmarshal(atlas.MakeUnmarshalTransformFunc( 22 | func(x []byte) (Uint64, error) { 23 | return Uint64(leb128.ToUInt64(x)), nil 24 | })). 25 | Complete() 26 | 27 | // Uint64 is an unsigned 64-bit variable-length-encoded integer. 28 | type Uint64 uint64 29 | 30 | // MarshalJSON converts a Uint64 to a json string and returns it. 31 | func (u Uint64) MarshalJSON() ([]byte, error) { 32 | return []byte(`"` + strconv.FormatUint(uint64(u), 10) + `"`), nil 33 | } 34 | 35 | // UnmarshalJSON converts a json string to a Uint64. 36 | func (u *Uint64) UnmarshalJSON(b []byte) error { 37 | val, err := strconv.ParseUint(strings.Trim(string(b), `"`), 10, 64) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | *u = Uint64(val) 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /types/uint64_test.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | cbor "github.com/ipfs/go-ipld-cbor" 8 | 9 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestUint64CBor(t *testing.T) { 14 | tf.UnitTest(t) 15 | 16 | v := Uint64(64) 17 | m, err := cbor.DumpObject(v) 18 | assert.NoError(t, err) 19 | var got Uint64 20 | err = cbor.DecodeInto(m, &got) 21 | assert.NoError(t, err) 22 | assert.Equal(t, v, got) 23 | } 24 | 25 | func TestUint64Json(t *testing.T) { 26 | tf.UnitTest(t) 27 | 28 | v := Uint64(64) 29 | m, err := json.Marshal(v) 30 | assert.NoError(t, err) 31 | assert.Equal(t, `"64"`, string(m)) 32 | var got Uint64 33 | err = json.Unmarshal(m, &got) 34 | assert.NoError(t, err) 35 | assert.Equal(t, v, got) 36 | } 37 | -------------------------------------------------------------------------------- /util/convert/convert.go: -------------------------------------------------------------------------------- 1 | package convert 2 | 3 | import ( 4 | "github.com/ipfs/go-cid" 5 | cbor "github.com/ipfs/go-ipld-cbor" 6 | "github.com/pkg/errors" 7 | 8 | "github.com/filecoin-project/go-filecoin/types" 9 | ) 10 | 11 | // ToCid gets the Cid for the argument passed in 12 | func ToCid(object interface{}) (cid.Cid, error) { 13 | cborNode, err := cbor.WrapObject(object, types.DefaultHashFunction, -1) 14 | if err != nil { 15 | return cid.Cid{}, errors.Wrap(err, "failed to get cid of proposal") 16 | } 17 | return cborNode.Cid(), nil 18 | } 19 | -------------------------------------------------------------------------------- /util/moresync/latch.go: -------------------------------------------------------------------------------- 1 | package moresync 2 | 3 | import "sync" 4 | 5 | // A Latch allows one or more routines to wait for the completion of a set of events. 6 | // After the events are complete, any waiting routines are released, and subsequent invocations 7 | // of `Wait` return immediately. 8 | // 9 | // It is conceptually similar to a sync.WaitGroup, primary differences being: 10 | // - the count is set once at construction; 11 | // - it is not an error for a latch to receive more than the specified `Done` count. 12 | type Latch struct { 13 | mutex sync.Mutex 14 | remaining uint 15 | complete chan struct{} 16 | } 17 | 18 | // NewLatch initializes a new latch with an initial `count`. 19 | func NewLatch(count uint) *Latch { 20 | latch := &Latch{ 21 | remaining: count, 22 | complete: make(chan struct{}), 23 | } 24 | if count == 0 { 25 | close(latch.complete) 26 | } 27 | return latch 28 | } 29 | 30 | // Count returns the latch's current count. 31 | func (latch *Latch) Count() uint { 32 | latch.mutex.Lock() 33 | defer latch.mutex.Unlock() 34 | return latch.remaining 35 | } 36 | 37 | // Done reduces the latch's count by one, releasing waiting routines if the resulting count is zero. 38 | // This is a no-op if the count is already zero. 39 | func (latch *Latch) Done() { 40 | latch.mutex.Lock() 41 | defer latch.mutex.Unlock() 42 | if latch.remaining > 0 { 43 | latch.remaining-- 44 | if latch.remaining == 0 { 45 | close(latch.complete) 46 | } 47 | } 48 | } 49 | 50 | // Wait blocks the calling routine until the count reaches zero. 51 | func (latch *Latch) Wait() { 52 | <-latch.complete 53 | } 54 | -------------------------------------------------------------------------------- /util/moresync/latch_test.go: -------------------------------------------------------------------------------- 1 | package moresync_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/stretchr/testify/assert" 8 | 9 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 10 | "github.com/filecoin-project/go-filecoin/util/moresync" 11 | ) 12 | 13 | func TestLatch(t *testing.T) { 14 | tf.UnitTest(t) 15 | 16 | t.Run("zero count is open", func(t *testing.T) { 17 | l := moresync.NewLatch(0) 18 | assert.Equal(t, uint(0), l.Count()) 19 | l.Wait() // Shouldn't block 20 | }) 21 | 22 | t.Run("wait blocks until done", func(t *testing.T) { 23 | l := moresync.NewLatch(1) 24 | assert.Equal(t, uint(1), l.Count()) 25 | waitDone := make(chan struct{}) 26 | 27 | go func() { 28 | l.Wait() // Should block at first. 29 | close(waitDone) 30 | }() 31 | 32 | select { 33 | case <-waitDone: 34 | assert.Fail(t, "wait didn't") 35 | case <-time.After(time.Millisecond): 36 | } 37 | assert.Equal(t, uint(1), l.Count()) 38 | 39 | l.Done() 40 | <-waitDone 41 | assert.Equal(t, uint(0), l.Count()) 42 | }) 43 | 44 | t.Run("counts down", func(t *testing.T) { 45 | l := moresync.NewLatch(5) 46 | for i := uint(5); i > 0; i-- { 47 | assert.Equal(t, i, l.Count()) 48 | l.Done() 49 | } 50 | assert.Equal(t, uint(0), l.Count()) 51 | l.Wait() // Shouldn't block 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /util/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "strconv" 5 | "strings" 6 | ) 7 | 8 | // Check ensures that we are using the correct version of go 9 | func Check(version string) bool { 10 | pieces := strings.Split(version, ".") 11 | 12 | if pieces[0] != "go1" { 13 | return false 14 | } 15 | 16 | minorVersion, _ := strconv.Atoi(pieces[1]) 17 | 18 | if minorVersion > 12 { 19 | return true 20 | } 21 | 22 | if minorVersion < 12 { 23 | return false 24 | } 25 | 26 | if len(pieces) < 3 { 27 | return false 28 | } 29 | 30 | patchVersion, _ := strconv.Atoi(pieces[2]) 31 | return patchVersion >= 1 32 | } 33 | -------------------------------------------------------------------------------- /util/version/version_test.go: -------------------------------------------------------------------------------- 1 | package version_test 2 | 3 | import ( 4 | "github.com/filecoin-project/go-filecoin/util/version" 5 | "testing" 6 | 7 | tf "github.com/filecoin-project/go-filecoin/testhelpers/testflags" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestCheck(t *testing.T) { 12 | tf.UnitTest(t) 13 | 14 | // Filecoin currently requires go >= 1.12.1 15 | assert.True(t, version.Check("go1.12.1")) 16 | assert.True(t, version.Check("go1.12.2")) 17 | assert.True(t, version.Check("go1.13")) 18 | assert.True(t, version.Check("go1.13.1")) 19 | 20 | assert.False(t, version.Check("go1.11")) 21 | assert.False(t, version.Check("go1.11.1")) 22 | assert.False(t, version.Check("go1.11.2")) 23 | assert.False(t, version.Check("go1.10")) 24 | assert.False(t, version.Check("go2")) 25 | } 26 | -------------------------------------------------------------------------------- /version/protocol_versions.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | import ( 4 | "github.com/filecoin-project/go-filecoin/types" 5 | ) 6 | 7 | // USER is the user network 8 | const USER = "alpha2" 9 | 10 | // DEVNET4 is the network name of devnet 11 | const DEVNET4 = "devnet4" 12 | 13 | // LOCALNET is the network name of localnet 14 | const LOCALNET = "localnet" 15 | 16 | // TEST is the network name for internal tests 17 | const TEST = "go-filecoin-test" 18 | 19 | // Protocol0 is the first protocol version 20 | const Protocol0 = 0 21 | 22 | // Protocol1 is the weight upgrade 23 | const Protocol1 = 1 24 | 25 | // ConfigureProtocolVersions configures all protocol upgrades for all known networks. 26 | // TODO: support arbitrary network names at "latest" protocol version so that only coordinated 27 | // network upgrades need to be represented here. See #3491. 28 | func ConfigureProtocolVersions(network string) (*ProtocolVersionTable, error) { 29 | return NewProtocolVersionTableBuilder(network). 30 | Add(USER, Protocol0, types.NewBlockHeight(0)). 31 | Add(USER, Protocol1, types.NewBlockHeight(43000)). 32 | Add(DEVNET4, Protocol0, types.NewBlockHeight(0)). 33 | Add(DEVNET4, Protocol1, types.NewBlockHeight(300)). 34 | Add(LOCALNET, Protocol1, types.NewBlockHeight(0)). 35 | Add(TEST, Protocol1, types.NewBlockHeight(0)). 36 | Build() 37 | } 38 | -------------------------------------------------------------------------------- /wallet/backend.go: -------------------------------------------------------------------------------- 1 | package wallet 2 | 3 | import ( 4 | "github.com/filecoin-project/go-filecoin/address" 5 | "github.com/filecoin-project/go-filecoin/types" 6 | ) 7 | 8 | // Backend is the interface to represent different storage backends 9 | // that can contain many addresses. 10 | type Backend interface { 11 | // Addresses returns a list of all accounts currently stored in this backend. 12 | Addresses() []address.Address 13 | 14 | // Contains returns true if this backend stores the passed in address. 15 | HasAddress(addr address.Address) bool 16 | 17 | // Sign cryptographically signs `data` using the private key `priv`. 18 | SignBytes(data []byte, addr address.Address) (types.Signature, error) 19 | 20 | // Verify cryptographically verifies that 'sig' is the signed hash of 'data' with 21 | // the public key `pk`. 22 | Verify(data, pk []byte, sig types.Signature) bool 23 | 24 | // GetKeyInfo will return the keyinfo associated with address `addr` 25 | // iff backend contains the addr. 26 | GetKeyInfo(addr address.Address) (*types.KeyInfo, error) 27 | } 28 | 29 | // Importer is a specialization of a wallet backend that can import 30 | // new keys into its permanent storage. Disk backed wallets can do this, 31 | // hardware wallets generally cannot. 32 | type Importer interface { 33 | // ImportKey imports the key described by the given keyinfo 34 | // into the backend 35 | ImportKey(ki *types.KeyInfo) error 36 | } 37 | -------------------------------------------------------------------------------- /wallet/util/util.go: -------------------------------------------------------------------------------- 1 | package walletutil 2 | 3 | import ( 4 | "github.com/minio/blake2b-simd" 5 | "github.com/pkg/errors" 6 | 7 | "github.com/filecoin-project/go-filecoin/crypto" 8 | ) 9 | 10 | // Sign cryptographically signs `data` using the private key `priv`. 11 | func Sign(priv, data []byte) ([]byte, error) { 12 | hash := blake2b.Sum256(data) 13 | // sign the content 14 | sig, err := crypto.Sign(priv, hash[:]) 15 | if err != nil { 16 | return nil, errors.Wrap(err, "Failed to sign data") 17 | } 18 | 19 | return sig, nil 20 | } 21 | 22 | // Verify cryptographically verifies that 'sig' is the signed hash of 'data' with 23 | // the public key `pk`. 24 | func Verify(pk []byte, data, signature []byte) (bool, error) { 25 | hash := blake2b.Sum256(data) 26 | // remove recovery id 27 | sig := signature[:len(signature)-1] 28 | return crypto.Verify(pk, hash[:], sig), nil 29 | } 30 | 31 | // Ecrecover returns an uncompressed public key that could produce the given 32 | // signature from data. 33 | // Note: The returned public key should not be used to verify `data` is valid 34 | // since a public key may have N private key pairs 35 | func Ecrecover(data, signature []byte) ([]byte, error) { 36 | hash := blake2b.Sum256(data) 37 | return crypto.EcRecover(hash[:], signature) 38 | } 39 | --------------------------------------------------------------------------------