Skip to content

Commit 95e0e04

Browse files
Chain: block producer (filecoin-project#119)
1 parent fc9ad76 commit 95e0e04

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+999
-239
lines changed

core/blockchain/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#
55

66
add_subdirectory(message_pool)
7+
add_subdirectory(production)
78

89
add_library(block_validator
910
impl/block_validator_impl.cpp
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#
2+
#Copyright Soramitsu Co., Ltd.All Rights Reserved.
3+
#SPDX - License - Identifier : Apache - 2.0
4+
#
5+
6+
add_library(block_producer
7+
impl/block_producer_impl.cpp
8+
)
9+
target_link_libraries(block_producer
10+
bls_provider
11+
outcome
12+
buffer
13+
address
14+
clock
15+
interpreter
16+
tipset
17+
ipfs_datastore_in_memory
18+
)

core/blockchain/production/block_generator.hpp

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include "common/outcome.hpp"
7+
#include "primitives/address/address.hpp"
8+
#include "primitives/block/block.hpp"
9+
#include "primitives/ticket/epost_ticket.hpp"
10+
#include "primitives/ticket/ticket.hpp"
11+
#include "vm/indices/indices.hpp"
12+
13+
namespace fc::blockchain::production {
14+
/**
15+
* @class Generating new blocks for chain's tipset
16+
*/
17+
class BlockProducer {
18+
protected:
19+
using Block = primitives::block::Block;
20+
using Address = primitives::address::Address;
21+
using EPostProof = primitives::ticket::EPostProof;
22+
using Ticket = primitives::ticket::Ticket;
23+
using Indices = vm::indices::Indices;
24+
25+
public:
26+
virtual ~BlockProducer() = default;
27+
28+
/**
29+
* @brief Generate new block
30+
* @param miner_address - source address
31+
* @param parent_tipset_id - id of the parent tipset
32+
* @param proof - evidence of mining permission
33+
* @param ticket - used ticket for election round
34+
* @return Generated full block
35+
*/
36+
virtual outcome::result<Block> generate(
37+
Address miner_address,
38+
const CID &parent_tipset_id,
39+
EPostProof proof,
40+
Ticket ticket,
41+
std::shared_ptr<Indices> indices) = 0;
42+
};
43+
44+
/**
45+
* @enum Block production errors
46+
*/
47+
enum class BlockProducerError {
48+
PARENT_TIPSET_NOT_FOUND = 1,
49+
PARENT_TIPSET_INVALID_CONTENT
50+
};
51+
} // namespace fc::blockchain::production
52+
53+
OUTCOME_HPP_DECLARE_ERROR(fc::blockchain::production, BlockProducerError);
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include "blockchain/production/impl/block_producer_impl.hpp"
7+
8+
#include <vector>
9+
10+
#include <gsl/span>
11+
#include "clock/chain_epoch_clock.hpp"
12+
#include "codec/cbor/cbor.hpp"
13+
#include "common/visitor.hpp"
14+
#include "primitives/cid/cid_of_cbor.hpp"
15+
#include "storage/amt/amt.hpp"
16+
#include "storage/ipfs/impl/in_memory_datastore.hpp"
17+
18+
namespace fc::blockchain::production {
19+
using clock::Time;
20+
using codec::cbor::decode;
21+
using crypto::signature::BlsSignature;
22+
using crypto::signature::Secp256k1Signature;
23+
using primitives::block::BlockHeader;
24+
using storage::amt::Amt;
25+
using storage::amt::Root;
26+
using storage::ipfs::InMemoryDatastore;
27+
using vm::message::SignedMessage;
28+
using vm::message::UnsignedMessage;
29+
30+
BlockProducerImpl::BlockProducerImpl(
31+
std::shared_ptr<IpfsDatastore> data_store,
32+
std::shared_ptr<MessageStorage> message_store,
33+
std::shared_ptr<UTCClock> utc_clock,
34+
std::shared_ptr<ChainEpochClock> epoch_clock,
35+
std::shared_ptr<WeightCalculator> weight_calculator,
36+
std::shared_ptr<BlsProvider> crypto_provider,
37+
std::shared_ptr<Interpreter> interpreter)
38+
: data_storage_{std::move(data_store)},
39+
message_storage_{std::move(message_store)},
40+
clock_{std::move(utc_clock)},
41+
epoch_{std::move(epoch_clock)},
42+
chain_weight_calculator_{std::move(weight_calculator)},
43+
bls_provider_{std::move(crypto_provider)},
44+
vm_interpreter_{std::move(interpreter)} {}
45+
46+
outcome::result<BlockProducer::Block> BlockProducerImpl::generate(
47+
primitives::address::Address miner_address,
48+
const CID &parent_tipset_id,
49+
EPostProof proof,
50+
Ticket ticket,
51+
std::shared_ptr<Indices> indices) {
52+
OUTCOME_TRY(parent_tipset, getTipset(parent_tipset_id));
53+
OUTCOME_TRY(
54+
vm_result,
55+
vm_interpreter_->interpret(data_storage_, parent_tipset, indices));
56+
OUTCOME_TRY(parent_weight,
57+
chain_weight_calculator_->calculateWeight(parent_tipset));
58+
std::vector<SignedMessage> messages =
59+
message_storage_->getTopScored(config::kBlockMaxMessagesCount);
60+
OUTCOME_TRY(msg_meta, getMessagesMeta(messages));
61+
std::vector<UnsignedMessage> bls_messages;
62+
std::vector<SignedMessage> secp_messages;
63+
std::vector<crypto::bls::Signature> bls_signatures;
64+
for (auto &&message : messages) {
65+
visit_in_place(
66+
message.signature,
67+
[&message, &bls_messages, &bls_signatures](
68+
const BlsSignature &signature) {
69+
bls_messages.emplace_back(std::move(message.message));
70+
bls_signatures.push_back(signature);
71+
},
72+
[&message, &secp_messages](const Secp256k1Signature &signature) {
73+
secp_messages.emplace_back(std::move(message));
74+
});
75+
}
76+
OUTCOME_TRY(bls_aggregate_sign,
77+
bls_provider_->aggregateSignatures(bls_signatures));
78+
Time now = clock_->nowUTC();
79+
OUTCOME_TRY(current_epoch, epoch_->epochAtTime(now));
80+
BlockHeader header{
81+
.miner = std::move(miner_address),
82+
.ticket = ticket,
83+
.epost_proof = std::move(proof),
84+
.parents = std::move(parent_tipset.cids),
85+
.parent_weight = parent_weight,
86+
.height = static_cast<uint64_t>(current_epoch),
87+
.parent_state_root = std::move(vm_result.state_root),
88+
.parent_message_receipts = std::move(vm_result.message_receipts),
89+
.messages = msg_meta.getCID(),
90+
.bls_aggregate = {std::move_iterator(bls_aggregate_sign.begin()),
91+
std::move_iterator(bls_aggregate_sign.end())},
92+
.timestamp = static_cast<uint64_t>(now.unixTime().count()),
93+
.block_sig = {}, // Block must be signed be Actor Miner
94+
.fork_signaling = 0};
95+
return Block{.header = std::move(header),
96+
.bls_messages = std::move(bls_messages),
97+
.secp_messages = std::move(secp_messages)};
98+
}
99+
100+
outcome::result<BlockProducerImpl::Tipset> BlockProducerImpl::getTipset(
101+
const CID &tipset_id) const {
102+
auto raw_data = data_storage_->get(tipset_id);
103+
if (raw_data.has_error()) {
104+
return BlockProducerError::PARENT_TIPSET_NOT_FOUND;
105+
}
106+
auto tipset = codec::cbor::decode<Tipset>(raw_data.value());
107+
if (tipset.has_error()) {
108+
return BlockProducerError::PARENT_TIPSET_INVALID_CONTENT;
109+
}
110+
return tipset.value();
111+
}
112+
113+
outcome::result<BlockProducerImpl::MsgMeta>
114+
BlockProducerImpl::getMessagesMeta(
115+
const std::vector<SignedMessage> &messages) {
116+
auto bls_backend = std::make_shared<InMemoryDatastore>();
117+
auto secp_backend = std::make_shared<InMemoryDatastore>();
118+
Amt bls_messages_amt{bls_backend};
119+
Amt secp_messages_amt{secp_backend};
120+
std::vector<SignedMessage> bls_messages;
121+
std::vector<SignedMessage> secp_messages;
122+
for (const auto &msg : messages) {
123+
visit_in_place(
124+
msg.signature,
125+
[&msg, &bls_messages](const BlsSignature &signature) {
126+
std::ignore = signature;
127+
bls_messages.push_back(msg);
128+
},
129+
[&msg, &secp_messages](const Secp256k1Signature &signature) {
130+
std::ignore = signature;
131+
secp_messages.push_back(msg);
132+
});
133+
}
134+
for (size_t index = 0; index < bls_messages.size(); ++index) {
135+
OUTCOME_TRY(message_cid,
136+
primitives::cid::getCidOfCbor(bls_messages.at(index)));
137+
OUTCOME_TRY(bls_messages_amt.setCbor(index, message_cid));
138+
}
139+
for (size_t index = 0; index < secp_messages.size(); ++index) {
140+
OUTCOME_TRY(message_cid,
141+
primitives::cid::getCidOfCbor(secp_messages.at(index)));
142+
OUTCOME_TRY(secp_messages_amt.setCbor(index, message_cid));
143+
}
144+
OUTCOME_TRY(bls_root_cid, bls_messages_amt.flush());
145+
OUTCOME_TRY(secp_root_cid, secp_messages_amt.flush());
146+
MsgMeta msg_meta{};
147+
msg_meta.bls_messages = bls_root_cid;
148+
msg_meta.secpk_messages = secp_root_cid;
149+
return msg_meta;
150+
}
151+
} // namespace fc::blockchain::production
152+
153+
OUTCOME_CPP_DEFINE_CATEGORY(fc::blockchain::production, BlockProducerError, e) {
154+
using fc::blockchain::production::BlockProducerError;
155+
switch (e) {
156+
case (BlockProducerError::PARENT_TIPSET_NOT_FOUND):
157+
return "Block Generator: failed to load parent tipset";
158+
case (BlockProducerError::PARENT_TIPSET_INVALID_CONTENT):
159+
return "Block Generator: failed to decode parent tipset content";
160+
}
161+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/**
2+
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include <memory>
7+
8+
#include "blockchain/message_pool/message_storage.hpp"
9+
#include "blockchain/production/block_producer.hpp"
10+
#include "blockchain/weight_calculator.hpp"
11+
#include "clock/chain_epoch_clock.hpp"
12+
#include "clock/utc_clock.hpp"
13+
#include "crypto/bls/bls_provider.hpp"
14+
#include "primitives/block/block.hpp"
15+
#include "primitives/tipset/tipset.hpp"
16+
#include "storage/ipfs/datastore.hpp"
17+
#include "vm/interpreter/interpreter.hpp"
18+
19+
namespace fc::blockchain::production {
20+
namespace config {
21+
// Max messages count in the Block
22+
constexpr size_t kBlockMaxMessagesCount = 1000;
23+
} // namespace config
24+
25+
/**
26+
* @class Block Generator implementation
27+
*/
28+
class BlockProducerImpl : public BlockProducer {
29+
protected:
30+
using MessageStorage = blockchain::message_pool::MessageStorage;
31+
using WeightCalculator = blockchain::weight::WeightCalculator;
32+
using ChainEpochClock = clock::ChainEpochClock;
33+
using UTCClock = clock::UTCClock;
34+
using BlsProvider = crypto::bls::BlsProvider;
35+
using MsgMeta = primitives::block::MsgMeta;
36+
using Tipset = primitives::tipset::Tipset;
37+
using IpfsDatastore = storage::ipfs::IpfsDatastore;
38+
using SignedMessage = vm::message::SignedMessage;
39+
using Interpreter = vm::interpreter::Interpreter;
40+
41+
public:
42+
/**
43+
* @brief Construct new Block Generator
44+
* @param data_store
45+
*/
46+
explicit BlockProducerImpl(
47+
std::shared_ptr<IpfsDatastore> data_store,
48+
std::shared_ptr<MessageStorage> message_store,
49+
std::shared_ptr<UTCClock> utc_clock,
50+
std::shared_ptr<ChainEpochClock> epoch_clock,
51+
std::shared_ptr<WeightCalculator> weight_calculator,
52+
std::shared_ptr<BlsProvider> crypto_provider,
53+
std::shared_ptr<Interpreter> interpreter);
54+
55+
outcome::result<Block> generate(Address miner_address,
56+
const CID &parent_tipset_id,
57+
EPostProof proof,
58+
Ticket ticket,
59+
std::shared_ptr<Indices> indices) override;
60+
61+
private:
62+
std::shared_ptr<IpfsDatastore> data_storage_;
63+
std::shared_ptr<MessageStorage> message_storage_;
64+
std::shared_ptr<UTCClock> clock_;
65+
std::shared_ptr<ChainEpochClock> epoch_;
66+
std::shared_ptr<WeightCalculator> chain_weight_calculator_;
67+
std::shared_ptr<BlsProvider> bls_provider_;
68+
std::shared_ptr<Interpreter> vm_interpreter_;
69+
70+
/**
71+
* @brief Load tipset from IPFS storage by CID
72+
* @param tipset_id - CID of the tipset
73+
* @return requested tipset or appropriate error
74+
*/
75+
outcome::result<Tipset> getTipset(const CID &tipset_id) const;
76+
77+
/**
78+
* @brief Generate messages meta-data
79+
* @param messages - messages to include in the new Block
80+
* @return Generated meta-data
81+
*/
82+
static outcome::result<MsgMeta> getMessagesMeta(
83+
const std::vector<SignedMessage> &messages);
84+
};
85+
} // namespace fc::blockchain::production

core/crypto/bls/bls_provider.hpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
#ifndef CRYPTO_BLS_PROVIDER_HPP
77
#define CRYPTO_BLS_PROVIDER_HPP
88

9-
#include <gsl/span>
9+
#include <vector>
1010

11+
#include <gsl/span>
1112
#include "crypto/bls/bls_types.hpp"
1213

1314
namespace fc::crypto::bls {
@@ -51,6 +52,14 @@ namespace fc::crypto::bls {
5152
gsl::span<const uint8_t> message,
5253
const Signature &signature,
5354
const PublicKey &key) const = 0;
55+
56+
/**
57+
* @brief Aggregate BLS signatures
58+
* @param signatures - signatures to aggregate
59+
* @return aggregated single signature
60+
*/
61+
virtual outcome::result<Signature> aggregateSignatures(
62+
const std::vector<Signature> &signatures) const = 0;
5463
};
5564
} // namespace fc::crypto::bls
5665

core/crypto/bls/bls_types.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ namespace fc::crypto::bls {
3232
SignatureGenerationFailed,
3333
SignatureVerificationFailed,
3434
InvalidPrivateKey,
35-
InvalidPublicKey
35+
InvalidPublicKey,
36+
AggregateError
3637
};
3738
};
3839

0 commit comments

Comments
 (0)