mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 19:22:37 +00:00
282 lines
7.4 KiB
C++
282 lines
7.4 KiB
C++
/*
|
|
This file is part of TON Blockchain Library.
|
|
|
|
TON Blockchain Library is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
TON Blockchain Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Copyright 2017-2020 Telegram Systems LLP
|
|
*/
|
|
|
|
#pragma once
|
|
#include "vm/cells.h"
|
|
#include "vm/cellslice.h"
|
|
#include "Ed25519.h"
|
|
#include "block/block-auto.h"
|
|
#include "block/block-parse.h"
|
|
|
|
#include "td/utils/Variant.h"
|
|
|
|
#include "SmartContract.h"
|
|
#include "SmartContractCode.h"
|
|
|
|
namespace ton {
|
|
namespace pchan {
|
|
|
|
//
|
|
// Payment channels
|
|
//
|
|
struct Config {
|
|
td::uint32 init_timeout{0};
|
|
td::uint32 close_timeout{0};
|
|
td::SecureString a_key;
|
|
td::SecureString b_key;
|
|
block::StdAddress a_addr;
|
|
block::StdAddress b_addr;
|
|
td::uint64 channel_id{0};
|
|
td::uint64 min_A_extra{0};
|
|
|
|
td::Ref<vm::Cell> serialize() const;
|
|
};
|
|
|
|
struct MsgInit {
|
|
td::uint64 inc_A{0};
|
|
td::uint64 inc_B{0};
|
|
td::uint64 min_A{0};
|
|
td::uint64 min_B{0};
|
|
td::uint64 channel_id{0};
|
|
|
|
td::Ref<vm::Cell> serialize() const;
|
|
};
|
|
|
|
struct Promise {
|
|
td::uint64 channel_id;
|
|
td::uint64 promise_A{0};
|
|
td::uint64 promise_B{0};
|
|
td::Ref<vm::Cell> serialize() const;
|
|
};
|
|
|
|
td::Ref<vm::Cell> maybe_sign(const td::Ref<vm::Cell>& msg, const td::Ed25519::PrivateKey* key);
|
|
td::Ref<vm::CellSlice> maybe_ref(td::Ref<vm::Cell> msg);
|
|
|
|
struct MsgClose {
|
|
td::uint64 extra_A{0};
|
|
td::uint64 extra_B{0};
|
|
td::Ref<vm::CellSlice> signed_promise;
|
|
td::Ref<vm::Cell> serialize() const;
|
|
};
|
|
|
|
struct MsgTimeout {
|
|
td::Ref<vm::Cell> serialize() const;
|
|
};
|
|
|
|
struct MsgPayout {
|
|
td::Ref<vm::Cell> serialize() const;
|
|
};
|
|
|
|
struct SignedPromise {
|
|
Promise promise;
|
|
td::optional<td::SecureString> o_signature;
|
|
|
|
bool unpack(td::Ref<vm::Cell> cell);
|
|
static td::SecureString signature(const td::Ed25519::PrivateKey* key, const td::Ref<vm::Cell>& promise);
|
|
static td::Ref<vm::Cell> create_and_serialize(td::Slice signature, const td::Ref<vm::Cell>& promise);
|
|
static td::Ref<vm::Cell> create_and_serialize(const td::Ed25519::PrivateKey* key, const td::Ref<vm::Cell>& promise);
|
|
};
|
|
|
|
struct StateInit {
|
|
bool signed_A{false};
|
|
bool signed_B{false};
|
|
td::uint64 min_A{0};
|
|
td::uint64 min_B{0};
|
|
td::uint64 A{0};
|
|
td::uint64 B{0};
|
|
td::uint32 expire_at{0};
|
|
|
|
td::Ref<vm::Cell> serialize() const;
|
|
};
|
|
|
|
struct StateClose {
|
|
bool signed_A{false};
|
|
bool signed_B{false};
|
|
td::uint64 promise_A{0};
|
|
td::uint64 promise_B{0};
|
|
td::uint64 A{0};
|
|
td::uint64 B{0};
|
|
td::uint32 expire_at{0};
|
|
};
|
|
|
|
struct StatePayout {
|
|
td::uint64 A{0};
|
|
td::uint64 B{0};
|
|
};
|
|
|
|
struct Data {
|
|
td::Ref<vm::Cell> config;
|
|
td::Ref<vm::Cell> state;
|
|
|
|
static td::Ref<vm::Cell> init_state();
|
|
|
|
td::Ref<vm::Cell> serialize() const;
|
|
};
|
|
|
|
template <class T>
|
|
struct MsgBuilder {
|
|
td::Ed25519::PrivateKey* a_key{nullptr};
|
|
td::Ed25519::PrivateKey* b_key{nullptr};
|
|
|
|
T&& with_a_key(td::Ed25519::PrivateKey* key) && {
|
|
a_key = key;
|
|
return static_cast<T&&>(*this);
|
|
}
|
|
T&& with_b_key(td::Ed25519::PrivateKey* key) && {
|
|
b_key = key;
|
|
return static_cast<T&&>(*this);
|
|
}
|
|
|
|
td::Ref<vm::Cell> finalize() && {
|
|
block::gen::ChanSignedMsg::Record rec;
|
|
auto msg = static_cast<T&&>(*this).msg.serialize();
|
|
rec.msg = vm::load_cell_slice_ref(msg);
|
|
rec.sig_A = maybe_ref(maybe_sign(msg, a_key));
|
|
rec.sig_B = maybe_ref(maybe_sign(msg, b_key));
|
|
block::gen::ChanOp::Record op_rec;
|
|
CHECK(tlb::csr_pack(op_rec.msg, rec));
|
|
LOG(ERROR) << op_rec.msg->size();
|
|
td::Ref<vm::Cell> res;
|
|
CHECK(tlb::pack_cell(res, op_rec));
|
|
return res;
|
|
}
|
|
};
|
|
|
|
struct MsgInitBuilder : public MsgBuilder<MsgInitBuilder> {
|
|
MsgInit msg;
|
|
|
|
MsgInitBuilder&& min_A(td::uint64 value) && {
|
|
msg.min_A = value;
|
|
return std::move(*this);
|
|
}
|
|
MsgInitBuilder&& min_B(td::uint64 value) && {
|
|
msg.min_B = value;
|
|
return std::move(*this);
|
|
}
|
|
MsgInitBuilder&& inc_A(td::uint64 value) && {
|
|
msg.inc_A = value;
|
|
return std::move(*this);
|
|
}
|
|
MsgInitBuilder&& inc_B(td::uint64 value) && {
|
|
msg.inc_B = value;
|
|
return std::move(*this);
|
|
}
|
|
MsgInitBuilder&& channel_id(td::uint64 value) && {
|
|
msg.channel_id = value;
|
|
return std::move(*this);
|
|
}
|
|
};
|
|
|
|
struct MsgTimeoutBuilder : public MsgBuilder<MsgTimeoutBuilder> {
|
|
MsgTimeout msg;
|
|
};
|
|
|
|
struct MsgPayoutBuilder : public MsgBuilder<MsgPayoutBuilder> {
|
|
MsgPayout msg;
|
|
};
|
|
|
|
struct MsgCloseBuilder : public MsgBuilder<MsgCloseBuilder> {
|
|
MsgClose msg;
|
|
|
|
MsgCloseBuilder&& extra_A(td::uint64 value) && {
|
|
msg.extra_A = value;
|
|
return std::move(*this);
|
|
}
|
|
MsgCloseBuilder&& extra_B(td::uint64 value) && {
|
|
msg.extra_B = value;
|
|
return std::move(*this);
|
|
}
|
|
MsgCloseBuilder&& signed_promise(td::Ref<vm::Cell> signed_promise) && {
|
|
msg.signed_promise = vm::load_cell_slice_ref(signed_promise);
|
|
return std::move(*this);
|
|
}
|
|
};
|
|
|
|
struct SignedPromiseBuilder {
|
|
Promise promise;
|
|
td::optional<td::SecureString> o_signature;
|
|
td::Ed25519::PrivateKey* key{nullptr};
|
|
|
|
SignedPromiseBuilder& with_key(td::Ed25519::PrivateKey* key) {
|
|
this->key = key;
|
|
return *this;
|
|
}
|
|
SignedPromiseBuilder& promise_A(td::uint64 value) {
|
|
promise.promise_A = value;
|
|
return *this;
|
|
}
|
|
SignedPromiseBuilder& promise_B(td::uint64 value) {
|
|
promise.promise_B = value;
|
|
return *this;
|
|
}
|
|
SignedPromiseBuilder& channel_id(td::uint64 value) {
|
|
promise.channel_id = value;
|
|
return *this;
|
|
}
|
|
SignedPromiseBuilder& signature(td::SecureString signature) {
|
|
o_signature = std::move(signature);
|
|
return *this;
|
|
}
|
|
|
|
bool check_signature(td::Slice signature, const td::Ed25519::PublicKey& pk) {
|
|
return pk.verify_signature(promise.serialize()->get_hash().as_slice(), signature).is_ok();
|
|
}
|
|
td::SecureString calc_signature() {
|
|
CHECK(key);
|
|
return SignedPromise::signature(key, promise.serialize());
|
|
}
|
|
td::Ref<vm::Cell> finalize() {
|
|
if (o_signature) {
|
|
return SignedPromise::create_and_serialize(o_signature.value().copy(), promise.serialize());
|
|
} else {
|
|
return SignedPromise::create_and_serialize(key, promise.serialize());
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace pchan
|
|
|
|
class PaymentChannel : public SmartContract {
|
|
public:
|
|
PaymentChannel(State state) : SmartContract(std::move(state)) {
|
|
}
|
|
|
|
struct Info {
|
|
pchan::Config config;
|
|
td::Variant<pchan::StateInit, pchan::StateClose, pchan::StatePayout> state;
|
|
std::string description;
|
|
};
|
|
td::Result<Info> get_info() const;
|
|
|
|
static td::Ref<PaymentChannel> create(State state) {
|
|
return td::Ref<PaymentChannel>(true, std::move(state));
|
|
}
|
|
static td::optional<td::int32> guess_revision(const vm::Cell::Hash& code_hash);
|
|
static td::Ref<PaymentChannel> create(const pchan::Config& config, td::int32 revision) {
|
|
State state;
|
|
state.code = SmartContractCode::get_code(SmartContractCode::PaymentChannel, revision);
|
|
pchan::Data data;
|
|
data.config = config.serialize();
|
|
pchan::StateInit init;
|
|
data.state = init.serialize();
|
|
state.data = data.serialize();
|
|
return create(std::move(state));
|
|
}
|
|
};
|
|
} // namespace ton
|