Ownership – Miscellaneous¶
Ownership checks¶
Ownership can be documented and checked by writing the ownership in brackets. For example, [m@Owned]
indicates
that m
is an owning reference at that particular point in the code. The compiler will generate an error if this
might not be the case. For example:
// m is Owned initially but must be Unowned at the end.
transaction spend(Money@Owned >> Unowned m) {
// implementation not shown
}
transaction testSpend(Money@Owned >> Unowned m) {
spend(m); [m@Unowned]; // OK
[m@Owned]; // COMPILE ERROR: m is Unowned here
}
Ownership checks in []
never change ownership; they only document and check what is known.
Getting rid of ownership¶
If ownership is no longer desired, disown
can be used to discard ownership. For example:
contract Money {
int amount;
transaction merge(Money@Owned >> Unowned mergeFrom) {
amount = amount + mergeFrom.amount;
[mergeFrom@Owned]; // As per declaration
disown mergeFrom;
// We absorbed the value of mergeFrom, so we need to throw it away.
// Since 'mergeFrom' is no longer an owning reference,
// it satisfies the 'Unowned' specification above
// and we don't get an error about losing an owned asset.
}
}
IMPORTANT: disown should be used only when you really want to throw something out. Above, disown is required because of the manual arithmetic used to manipulate amount inside the implementation of Money, but it is not needed in most normal code.
Invoking transactions¶
The compiler checks each invocation to make sure it is permitted according to the ownership of the transaction arguments. For example:
transaction spend(Money@Owned >> Unowned m) {
// implementation not shown
};
transaction print(Money@Unowned m) {
// implementation not shown
}
transaction test() {
Money m = ... // assume m is now owned.
print(m); // m is still Owned
spend(m); // m is now Unowned
spend(m); // COMPILE ERROR: spend() requires Owned input, but m is Unowned here
}
Handling Errors¶
Errors can be flagged with revert
, which stops execution and discards all of the changes that have occurred since the outermost transaction started. A description of the error can be provided as well. An example of usage is given below.
transaction checkAmount(Money@Unowned m) {
if (m.getAmount() < 0) {
revert("Money must have an amount greater than 0");
}
}
Return¶
Return statements affect the type of the returned expression according to the declared return type. For example:
asset contract Candy {}
contract VendingMachine {
transaction dispenseCandy() returns Candy@Owned {
Candy c = ... // Get an owned reference somehow
return c; // Satisfies return type because ownership of c is transferred to the caller
// No accidental loss of c here because c is no longer Owned
}