2018-02-04 03:22:01 +01:00
|
|
|
// Matrix Construct
|
|
|
|
//
|
|
|
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
|
|
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
|
|
|
//
|
|
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
|
|
// copyright notice and this permission notice is present in all copies. The
|
|
|
|
// full license for this software is available in the LICENSE file.
|
2017-09-26 06:42:07 +02:00
|
|
|
|
|
|
|
#pragma once
|
2017-10-25 18:47:03 +02:00
|
|
|
#define HAVE_IRCD_M_VM_H
|
2017-09-26 06:42:07 +02:00
|
|
|
|
2017-11-16 02:48:25 +01:00
|
|
|
/// Matrix Virtual Machine
|
|
|
|
///
|
2017-10-25 18:47:03 +02:00
|
|
|
namespace ircd::m::vm
|
2017-09-26 06:42:07 +02:00
|
|
|
{
|
2017-11-30 20:01:14 +01:00
|
|
|
enum fault :uint;
|
2018-02-28 07:53:44 +01:00
|
|
|
struct error; // custom exception
|
|
|
|
struct opts;
|
2017-11-16 02:48:25 +01:00
|
|
|
struct eval;
|
2018-03-13 03:07:41 +01:00
|
|
|
struct accepted;
|
2017-11-16 02:48:25 +01:00
|
|
|
|
2018-02-28 07:53:44 +01:00
|
|
|
using fault_t = std::underlying_type<fault>::type;
|
2017-09-28 03:31:21 +02:00
|
|
|
using closure = std::function<void (const event &)>;
|
|
|
|
using closure_bool = std::function<bool (const event &)>;
|
2017-09-26 06:42:07 +02:00
|
|
|
|
2017-11-16 02:48:25 +01:00
|
|
|
extern struct log::log log;
|
|
|
|
extern uint64_t current_sequence;
|
2018-03-13 03:07:41 +01:00
|
|
|
extern ctx::shared_view<accepted> accept;
|
2018-02-28 07:53:44 +01:00
|
|
|
extern const opts default_opts;
|
2017-09-26 06:42:07 +02:00
|
|
|
|
2018-03-08 18:44:44 +01:00
|
|
|
event::id::buf commit(const m::event &, const opts & = default_opts);
|
|
|
|
event::id::buf commit(json::iov &event, const json::iov &content, const opts & = default_opts);
|
2017-11-16 02:48:25 +01:00
|
|
|
}
|
|
|
|
|
2018-02-08 22:23:01 +01:00
|
|
|
/// Event Evaluation Device
|
|
|
|
///
|
|
|
|
/// This object conducts the evaluation of an event or a tape of multiple
|
|
|
|
/// events. An event is evaluated in an attempt to execute it. Events which
|
|
|
|
/// fail during evaluation won't be executed; such is the case for events which
|
|
|
|
/// have already been executed, or events which are invalid or lead to invalid
|
|
|
|
/// transitions or actions of the machine etc.
|
|
|
|
///
|
|
|
|
struct ircd::m::vm::eval
|
|
|
|
{
|
2018-02-28 07:53:44 +01:00
|
|
|
const vm::opts *opts {&default_opts};
|
2018-02-08 22:23:01 +01:00
|
|
|
db::txn txn{*dbs::events};
|
|
|
|
|
|
|
|
fault operator()(const event &);
|
|
|
|
|
2018-02-28 07:53:44 +01:00
|
|
|
eval(const event &, const vm::opts & = default_opts);
|
|
|
|
eval(const vm::opts &);
|
2018-02-08 22:23:01 +01:00
|
|
|
eval() = default;
|
|
|
|
|
|
|
|
friend string_view reflect(const fault &);
|
|
|
|
};
|
|
|
|
|
2017-11-30 20:01:14 +01:00
|
|
|
/// Evaluation faults. These are reasons which evaluation has halted but may
|
|
|
|
/// continue after the user defaults the fault. They are basically types of
|
2018-02-28 07:53:44 +01:00
|
|
|
/// interrupts and traps, which are supposed to be recoverable. Only the
|
|
|
|
/// GENERAL protection fault (#gp) is an abort and is not supposed to be
|
|
|
|
/// recoverable. The fault codes have the form of bitflags so they can be
|
|
|
|
/// used in masks; outside of that case only one fault is dealt with at
|
|
|
|
/// a time so they can be switched as they appear in the enum.
|
2017-11-30 20:01:14 +01:00
|
|
|
///
|
|
|
|
enum ircd::m::vm::fault
|
|
|
|
:uint
|
|
|
|
{
|
2018-02-28 07:53:44 +01:00
|
|
|
ACCEPT = 0x00, ///< No fault.
|
|
|
|
EXISTS = 0x01, ///< Replaying existing event. (#ex)
|
|
|
|
INVALID = 0x02, ///< Non-conforming event format. (#ud)
|
|
|
|
DEBUGSTEP = 0x04, ///< Debug step. (#db)
|
|
|
|
BREAKPOINT = 0x08, ///< Debug breakpoint. (#bp)
|
|
|
|
GENERAL = 0x10, ///< General protection fault. (#gp)
|
|
|
|
EVENT = 0x20, ///< Eval requires addl events in the ef register (#ef)
|
|
|
|
STATE = 0x40, ///< Required state is missing (#st)
|
2017-11-30 20:01:14 +01:00
|
|
|
};
|
2018-02-28 07:53:44 +01:00
|
|
|
|
|
|
|
/// Evaluation Options
|
|
|
|
struct ircd::m::vm::opts
|
|
|
|
{
|
2018-03-08 18:54:39 +01:00
|
|
|
// Hash and include hashes object.
|
|
|
|
bool hash {true};
|
|
|
|
|
|
|
|
// Sign and include signatures object
|
|
|
|
bool sign {true};
|
|
|
|
|
2018-02-28 07:53:44 +01:00
|
|
|
/// Make writes to database
|
|
|
|
bool write {true};
|
|
|
|
|
|
|
|
/// Apply effects of the eval
|
|
|
|
bool effects {true};
|
|
|
|
|
|
|
|
/// Broadcast to clients/servers
|
|
|
|
bool notify {true};
|
|
|
|
|
2018-03-13 03:34:54 +01:00
|
|
|
/// False to allow a dirty conforms report (not recommended).
|
|
|
|
bool conforming {true};
|
|
|
|
|
|
|
|
/// Mask of conformity failures to allow without considering dirty.
|
2018-02-28 07:53:44 +01:00
|
|
|
event::conforms non_conform;
|
|
|
|
|
2018-03-13 03:34:54 +01:00
|
|
|
/// If the event was already checked before the eval, set this to true
|
|
|
|
/// and include the report (see below).
|
|
|
|
bool conformed {false};
|
|
|
|
|
|
|
|
/// When conformed=true, this report will be included instead of generating
|
|
|
|
/// one during the eval. This is useful if a conformity check was already
|
|
|
|
/// done before eval.
|
|
|
|
event::conforms report;
|
|
|
|
|
2018-03-09 00:55:54 +01:00
|
|
|
/// Toggles whether event may be considered a "present event" and may
|
|
|
|
/// update the optimized present state table of the room if it is proper.
|
|
|
|
bool present {true};
|
|
|
|
|
|
|
|
/// Toggles whether the state btree is updated; this should be consistently
|
|
|
|
/// true or false for all events in a room.
|
|
|
|
bool history {true};
|
|
|
|
|
2018-02-28 07:53:44 +01:00
|
|
|
/// Bypass check for event having already been evaluated so it can be
|
|
|
|
/// replayed through the system (not recommended).
|
|
|
|
bool replays {false};
|
|
|
|
|
|
|
|
/// TODO: Y
|
|
|
|
bool prev_check_exists {true};
|
|
|
|
|
2018-03-09 00:55:54 +01:00
|
|
|
/// TODO: Y
|
|
|
|
bool head_must_exist {false};
|
|
|
|
|
2018-02-28 07:53:44 +01:00
|
|
|
/// Mask of faults that are not thrown as exceptions out of eval(). If
|
|
|
|
/// masked, the fault is returned from eval(). By default, the EXISTS
|
|
|
|
/// fault is masked which means existing events won't kill eval loops
|
|
|
|
/// as well as the debug related.
|
|
|
|
fault_t nothrows
|
|
|
|
{
|
|
|
|
EXISTS | DEBUGSTEP | BREAKPOINT
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Mask of faults that are logged to the error facility in vm::log.
|
|
|
|
fault_t errorlog
|
|
|
|
{
|
|
|
|
~(EXISTS | DEBUGSTEP | BREAKPOINT)
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Mask of faults that are logged to the warning facility in vm::log
|
|
|
|
fault_t warnlog
|
|
|
|
{
|
|
|
|
EXISTS
|
|
|
|
};
|
|
|
|
|
2018-03-08 18:54:39 +01:00
|
|
|
/// Whether to log a debug message before commit
|
|
|
|
bool debuglog_precommit {false};
|
|
|
|
|
2018-02-28 07:53:44 +01:00
|
|
|
/// Whether to log a debug message on successful eval.
|
|
|
|
bool debuglog_accept {false};
|
|
|
|
|
|
|
|
/// Whether to log an info message on successful eval.
|
|
|
|
bool infolog_accept {false};
|
|
|
|
};
|
|
|
|
|
2018-03-13 03:07:41 +01:00
|
|
|
struct ircd::m::vm::accepted
|
|
|
|
:m::event
|
|
|
|
{
|
|
|
|
ctx::ctx *context;
|
|
|
|
const vm::opts *opts;
|
|
|
|
const event::conforms *report;
|
|
|
|
std::string strung;
|
|
|
|
|
|
|
|
accepted(const m::event &event,
|
|
|
|
const vm::opts *const &opts,
|
|
|
|
const event::conforms *const &report);
|
|
|
|
};
|
|
|
|
|
2018-02-28 07:53:44 +01:00
|
|
|
struct ircd::m::vm::error
|
|
|
|
:m::error
|
|
|
|
{
|
|
|
|
vm::fault code;
|
|
|
|
|
|
|
|
template<class... args> error(const fault &code, const char *const &fmt, args&&... a);
|
|
|
|
template<class... args> error(const char *const &fmt, args&&... a);
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class... args>
|
|
|
|
ircd::m::vm::error::error(const fault &code,
|
|
|
|
const char *const &fmt,
|
|
|
|
args&&... a)
|
|
|
|
:m::error
|
|
|
|
{
|
|
|
|
http::NOT_MODIFIED, "M_VM_FAULT", fmt, std::forward<args>(a)...
|
|
|
|
}
|
|
|
|
,code
|
|
|
|
{
|
|
|
|
code
|
|
|
|
}
|
|
|
|
{}
|
|
|
|
|
|
|
|
template<class... args>
|
|
|
|
ircd::m::vm::error::error(const char *const &fmt,
|
|
|
|
args&&... a)
|
|
|
|
:m::error
|
|
|
|
{
|
|
|
|
http::INTERNAL_SERVER_ERROR, "M_VM_FAULT", fmt, std::forward<args>(a)...
|
|
|
|
}
|
|
|
|
,code
|
|
|
|
{
|
|
|
|
fault::GENERAL
|
|
|
|
}
|
|
|
|
{}
|