Message
In Everscale, smart-contracts communicate between each other and with non-blockchain applications by means of an asynchronous message passing.
Technically, a message is a data structure encoding one of the following:
- desired function call at a destination smart-contract, optionally attaching some coins.
- event log record to signal external observers about some significant state being reached
We distinguish 3 types1 of messages:
- External — messages sent by non-blockchain applications
- Internal — messages sent by smart-contracts between each other
- Event — a log record signaling some special state for external observers
pub struct Message {
header: CommonMsgInfo,
init: Option<StateInit>,
body: Option<SliceData>,
body_to_ref: Option<bool>,
init_to_ref: Option<bool>,
}
The last two fields body_to_ref
and init_to_ref
are used only for serialization purpose, hence not considered in this document.
Message Header
Any message has a message header: a data-structure defining, among other things, the message type and source and destination addresses.
The message header defines its type. It is described by the following enumeration:
pub enum CommonMsgInfo {
IntMsgInfo(InternalMessageHeader),
ExtInMsgInfo(ExternalInboundMessageHeader),
ExtOutMsgInfo(ExtOutMessageHeader),
}
Internal Message
Within Everscale blockchain, smart-contracts communicate with each other by exchanging messages. Messages sent by smart-contracts are called internal.
They are opposed to external messages that are sent by off-chain applications to smart-contracts.
The message header of an internal message is defined as follows:
pub struct InternalMessageHeader {
pub ihr_disabled: bool,
pub bounce: bool,
pub bounced: bool,
pub src: MsgAddressIntOrNone,
pub dst: MsgAddressInt,
pub value: CurrencyCollection,
pub ihr_fee: Grams,
pub fwd_fee: Grams,
pub created_lt: u64,
pub created_at: UnixTime32,
}
InternalMessageHeader fields
Field | Description |
---|---|
ihr_disabled | IHR routing protocol disabled, always true |
bounce | Should the answer message be generated in case of an error |
bounced | Is this message was auto-generated by error handling |
src | Message source address |
dst | Message destination address |
value | Amount of coins attached to the message |
ihr_fee | IHR fee amount, always 0 |
fwd_fee | Message delivery fee amount |
created_lt | Message creation logic time |
created_at | Message creation time in Epoch |
Some clarifications:
bounced
flag is set when the message itself was auto-generated as a result of an error. If the message with bounced flag leads to an error itself, the next bounced message will not be generated.value
is measured in Nano Evers ()reated_lt
is a monotonically increasing counter, thanks to this field, each new generated message is unique, even if the message payload is the same. The message creation logic time is also used to guarantee order of delivery. We do not dive deep into this question, because it is protocol-level details.
External Message
External messages are created outside of the blockchain and get sent through specially distinguished validator nodes called DApp Servers2.
External message header is defined as follows:
pub struct ExternalInboundMessageHeader {
pub src: MsgAddressExt,
pub dst: MsgAddressInt,
pub import_fee: Grams,
}
- Fields
src
anddst
are source and destination addresses. - Field
import_fee
should have been the value paid to the validator for processing an external message. But in the current node, this field is not used. Hence, the fee is not paid. We reported this issue to the developers. - The source address for an external message is always set to
AddrNone
.
pub enum MsgAddressExt {
AddrNone,
AddrExtern(MsgAddrExt),
}
The second variant AddrExtern
is not supported currently.
Events
Event can be considered as a log record. It is used to signal external observers of reaching some significant state in a smart-contract.
Usually, observers are external non-blockchain applications that constantly monitor blockchain state3. Other smart-contracts are not able to catch events.
pub struct ExtOutMessageHeader {
pub src: MsgAddressIntOrNone,
pub dst: MsgAddressExt,
pub created_lt: u64,
pub created_at: UnixTime32,
}
pub enum MsgAddressIntOrNone {
None,
Some(MsgAddressInt)
}
- Transaction Executor automatically assigns the source address
src
to be equal to the smart-contract address emitting the event. - The destination address
dst
may contain any identifier. It is included for easier integration with off-chain applications, i.e. applications can monitor emitted events based on their destination address, and consume only those events destined to their custom identifier. - Fields
created_lt
,created_at
defines the logical creation time and epoch creation time.
Reference
- In the original TON, message dichotomy is different: they distinguish 4 types of messages:
(inbound + outbound) * (internal + external)
. We find this dichotomy a bit tedious to use in practice↩ - In the current protocol implementation, not all validator nodes process external messages. This is subject to change in the future protocol versions↩
- For example, by sending GraphQL requests to the DApp-server↩