Skip to content

Commit c884223

Browse files
committed
Chain block production implementation
1 parent 7284eae commit c884223

File tree

13 files changed

+363
-20
lines changed

13 files changed

+363
-20
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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#
2+
#Copyright Soramitsu Co., Ltd.All Rights Reserved.
3+
#SPDX - License - Identifier : Apache - 2.0
4+
#
5+
6+
add_library(chain_block_production
7+
impl/block_generator_impl.cpp
8+
)
9+
target_link_libraries(chain_block_production
10+
bls_provider
11+
outcome
12+
)

core/blockchain/production/block_generator.hpp

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,34 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
#include <memory>
7-
8-
#include "blockchain/message_pool/message_storage.hpp"
9-
#include "storage/ipfs/datastore.hpp"
10-
#include "primitives/tipset/tipset.hpp"
6+
#include "primitives/address/address.hpp"
117
#include "primitives/block/block.hpp"
12-
#include "primitives/cid/cid.hpp"
8+
#include "primitives/ticket/epost_ticket.hpp"
9+
#include "primitives/ticket/ticket.hpp"
10+
#include "vm/indices/indices.hpp"
11+
#include "common/outcome.hpp"
1312

1413
namespace fc::blockchain::production {
1514
class BlockGenerator {
16-
using fc::blockchain::message_pool::MessageStorage;
17-
using fc::primitives::tipset::Tipset;
18-
using fc::storage::ipfs::IpfsDataStore;
19-
using primitives::block::BlockHeader;
15+
protected:
16+
using Block = primitives::block::Block;
17+
using Address = primitives::address::Address;
18+
using EPostProof = primitives::ticket::EPostProof;
19+
using Ticket = primitives::ticket::Ticket;
20+
using Indices = vm::indices::Indices;
2021

2122
public:
22-
BlockGenerator(std::shared_ptr<IpfsDataStore> data_store,
23-
std::shared_ptr<MessageStorage> messages_store);
24-
23+
virtual ~BlockGenerator() = default;
2524

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

core/crypto/bls/impl/bls_provider_impl.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,24 @@ namespace fc::crypto::bls {
8686
digest.begin());
8787
return digest;
8888
}
89+
90+
outcome::result<Signature> BlsProviderImpl::aggregateSignatures(
91+
const std::vector<Signature> &signatures) const {
92+
Signature signature;
93+
const uint8_t *flat_bytes =
94+
reinterpret_cast<const uint8_t *>(signatures.data());
95+
size_t flat_size = sizeof(Signature) * signatures.size();
96+
AggregateResponse *response = ::aggregate(flat_bytes, flat_size);
97+
if (response == nullptr) {
98+
return Errors::InternalError;
99+
}
100+
auto free_response =
101+
gsl::finally([response]() { destroy_aggregate_response(response); });
102+
std::move(std::begin(response->signature),
103+
std::end(response->signature),
104+
signature.begin());
105+
return signature;
106+
}
89107
}; // namespace fc::crypto::bls
90108

91109
OUTCOME_CPP_DEFINE_CATEGORY(fc::crypto::bls, Errors, e) {
@@ -103,6 +121,8 @@ OUTCOME_CPP_DEFINE_CATEGORY(fc::crypto::bls, Errors, e) {
103121
return "BLS provider: signature generation failed";
104122
case (Errors::SignatureVerificationFailed):
105123
return "BLS provider: signature verification failed";
124+
case (Errors::AggregateError):
125+
return "BLS provider: signatures aggregating failed";
106126
default:
107127
return "BLS provider: unknown error";
108128
}

core/crypto/bls/impl/bls_provider_impl.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ namespace fc::crypto::bls {
2323
const Signature &signature,
2424
const PublicKey &key) const override;
2525

26+
outcome::result<Signature> aggregateSignatures(
27+
const std::vector<Signature> &signatures) const override;
28+
2629
private:
2730
/**
2831
* @brief Generate BLS message digest

0 commit comments

Comments
 (0)