Skip to content
This repository was archived by the owner on Feb 8, 2025. It is now read-only.

Commit 0ded2d4

Browse files
authored
Merge pull request #256 from zallo-labs/Z-295-policy-events
Z 295 policy events
2 parents a9090bb + 0d46162 commit 0ded2d4

File tree

116 files changed

+1562
-762
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+1562
-762
lines changed

.github/workflows/tests.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ jobs:
110110
services:
111111
redis:
112112
image: redis
113+
ports:
114+
- 6379:6379
113115
options: >-
114116
--health-cmd "redis-cli ping"
115117
--health-interval 10s
File renamed without changes.

api/dbschema/default.esdl

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module default {
1212
upgradedAtBlock: bigint { constraint min_value(0); }
1313
photo: Url;
1414
required property active := exists .upgradedAtBlock;
15-
multi policies: Policy { on source delete delete target; on target delete allow; }
15+
multi link policies := (select .<account[is Policy] filter .isLatest);
1616
multi link proposals := .<account[is Proposal];
1717
multi link transactions := .<account[is Transaction];
1818
multi link messages := .<account[is Message];

api/dbschema/edgeql-js/__spec__.ts

+4-4
Large diffs are not rendered by default.

api/dbschema/edgeql-js/modules/default.ts

+39-38
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,12 @@ export type $AccountλShape = $.typeutil.flatten<Omit<$LabelledλShape, "address
101101
"implementation": $.PropertyDesc<$Address, $.Cardinality.One, false, false, false, false>;
102102
"photo": $.PropertyDesc<$Url, $.Cardinality.AtMostOne, false, false, false, false>;
103103
"salt": $.PropertyDesc<$Bytes32, $.Cardinality.One, false, false, false, false>;
104-
"policies": $.LinkDesc<$Policy, $.Cardinality.Many, {}, false, false, false, false>;
105-
"approvers": $.LinkDesc<$Approver, $.Cardinality.Many, {}, false, true, false, false>;
106104
"messages": $.LinkDesc<$Message, $.Cardinality.Many, {}, false, true, false, false>;
107105
"proposals": $.LinkDesc<$Proposal, $.Cardinality.Many, {}, false, true, false, false>;
108106
"transactions": $.LinkDesc<$Transaction, $.Cardinality.Many, {}, false, true, false, false>;
109107
"transfers": $.LinkDesc<$Transfer, $.Cardinality.Many, {}, false, true, false, false>;
108+
"policies": $.LinkDesc<$Policy, $.Cardinality.Many, {}, false, true, false, false>;
109+
"approvers": $.LinkDesc<$Approver, $.Cardinality.Many, {}, false, true, false, false>;
110110
"<account[is Proposal]": $.LinkDesc<$Proposal, $.Cardinality.Many, {}, false, false, false, false>;
111111
"<account[is Message]": $.LinkDesc<$Message, $.Cardinality.Many, {}, false, false, false, false>;
112112
"<account[is Transaction]": $.LinkDesc<$Transaction, $.Cardinality.Many, {}, false, false, false, false>;
@@ -437,12 +437,17 @@ export type $PolicyStateλShape = $.typeutil.flatten<_std.$Object_8ce8c71ee4fa5f
437437
"proposal": $.LinkDesc<$Transaction, $.Cardinality.AtMostOne, {}, false, false, false, false>;
438438
"initState": $.PropertyDesc<_std.$bool, $.Cardinality.One, false, true, false, false>;
439439
"isDraft": $.PropertyDesc<_std.$bool, $.Cardinality.One, false, true, false, false>;
440-
"latest": $.LinkDesc<$Policy, $.Cardinality.AtMostOne, {}, false, true, false, false>;
440+
"latest": $.LinkDesc<$PolicyState, $.Cardinality.AtMostOne, {}, false, true, false, false>;
441441
"isActive": $.PropertyDesc<_std.$bool, $.Cardinality.One, false, true, false, false>;
442+
"isLatest": $.PropertyDesc<_std.$bool, $.Cardinality.One, false, false, false, true>;
442443
"<draft[is PolicyState]": $.LinkDesc<$PolicyState, $.Cardinality.Many, {}, false, false, false, false>;
443444
"<draft[is Policy]": $.LinkDesc<$Policy, $.Cardinality.Many, {}, false, false, false, false>;
444445
"<draft[is RemovedPolicy]": $.LinkDesc<$RemovedPolicy, $.Cardinality.Many, {}, false, false, false, false>;
446+
"<latest[is RemovedPolicy]": $.LinkDesc<$RemovedPolicy, $.Cardinality.Many, {}, false, false, false, false>;
447+
"<latest[is Policy]": $.LinkDesc<$Policy, $.Cardinality.Many, {}, false, false, false, false>;
448+
"<latest[is PolicyState]": $.LinkDesc<$PolicyState, $.Cardinality.Many, {}, false, false, false, false>;
445449
"<draft": $.LinkDesc<$.ObjectType, $.Cardinality.Many, {}, false, false, false, false>;
450+
"<latest": $.LinkDesc<$.ObjectType, $.Cardinality.Many, {}, false, false, false, false>;
446451
}>;
447452
type $PolicyState = $.ObjectType<"default::PolicyState", $PolicyStateλShape, null, [
448453
..._std.$Object_8ce8c71ee4fa5f73840c22d7eaa58588['__exclusives__'],
@@ -461,15 +466,11 @@ export type $PolicyλShape = $.typeutil.flatten<$PolicyStateλShape & {
461466
"threshold": $.PropertyDesc<$uint16, $.Cardinality.One, false, false, false, false>;
462467
"<policy[is Message]": $.LinkDesc<$Message, $.Cardinality.Many, {}, false, false, false, false>;
463468
"<policy[is Transaction]": $.LinkDesc<$Transaction, $.Cardinality.Many, {}, false, false, false, false>;
464-
"<policies[is Account]": $.LinkDesc<$Account, $.Cardinality.Many, {}, false, false, false, false>;
465469
"<spentBy[is Transfer]": $.LinkDesc<$Transfer, $.Cardinality.Many, {}, false, false, false, false>;
466-
"<latest[is PolicyState]": $.LinkDesc<$PolicyState, $.Cardinality.Many, {}, false, false, false, false>;
467-
"<latest[is Policy]": $.LinkDesc<$Policy, $.Cardinality.Many, {}, false, false, false, false>;
468-
"<latest[is RemovedPolicy]": $.LinkDesc<$RemovedPolicy, $.Cardinality.Many, {}, false, false, false, false>;
469470
"<spentBy[is Transferlike]": $.LinkDesc<$Transferlike, $.Cardinality.Many, {}, false, false, false, false>;
470471
"<spentBy[is TransferApproval]": $.LinkDesc<$TransferApproval, $.Cardinality.Many, {}, false, false, false, false>;
471472
"<policy[is Proposal]": $.LinkDesc<$Proposal, $.Cardinality.Many, {}, false, false, false, false>;
472-
"<latest": $.LinkDesc<$.ObjectType, $.Cardinality.Many, {}, false, false, false, false>;
473+
"<policies[is Account]": $.LinkDesc<$Account, $.Cardinality.Many, {}, false, false, false, false>;
473474
"<policies": $.LinkDesc<$.ObjectType, $.Cardinality.Many, {}, false, false, false, false>;
474475
"<policy": $.LinkDesc<$.ObjectType, $.Cardinality.Many, {}, false, false, false, false>;
475476
"<spentBy": $.LinkDesc<$.ObjectType, $.Cardinality.Many, {}, false, false, false, false>;
@@ -738,8 +739,8 @@ const TransfersConfig: $.$expr_PathNode<$.TypeSet<$TransfersConfig, $.Cardinalit
738739
export type $UserλShape = $.typeutil.flatten<_std.$Object_8ce8c71ee4fa5f73840c22d7eaa58588λShape & {
739740
"primaryAccount": $.LinkDesc<$Account, $.Cardinality.AtMostOne, {}, false, false, false, false>;
740741
"approvers": $.LinkDesc<$Approver, $.Cardinality.Many, {}, false, true, false, false>;
741-
"accounts": $.LinkDesc<$Account, $.Cardinality.Many, {}, false, true, false, false>;
742742
"contacts": $.LinkDesc<$Contact, $.Cardinality.Many, {}, false, true, false, false>;
743+
"accounts": $.LinkDesc<$Account, $.Cardinality.Many, {}, false, true, false, false>;
743744
"<user[is Approver]": $.LinkDesc<$Approver, $.Cardinality.Many, {}, false, false, false, false>;
744745
"<user[is current_approver]": $.LinkDesc<$current_approver, $.Cardinality.Many, {}, false, false, false, false>;
745746
"<user[is Contact]": $.LinkDesc<$Contact, $.Cardinality.Many, {}, false, false, false, false>;
@@ -921,33 +922,6 @@ function as_decimal(...args: any[]) {
921922
}) as any;
922923
};
923924

924-
type latestPolicyλFuncExpr<
925-
P1 extends $.TypeSet<$Account>,
926-
P2 extends _.castMaps.orScalarLiteral<$.TypeSet<_std.$number>>,
927-
> = $.$expr_Function<
928-
$Policy, $.cardutil.overrideLowerBound<$.cardutil.multiplyCardinalities<$.cardutil.paramCardinality<P1>, $.cardutil.paramCardinality<P2>>, 'Zero'>
929-
>;
930-
function latestPolicy<
931-
P1 extends $.TypeSet<$Account>,
932-
P2 extends _.castMaps.orScalarLiteral<$.TypeSet<_std.$number>>,
933-
>(
934-
account: P1,
935-
key: P2,
936-
): latestPolicyλFuncExpr<P1, P2>;
937-
function latestPolicy(...args: any[]) {
938-
const {returnType, cardinality, args: positionalArgs, namedArgs} = _.syntax.$resolveOverload('default::latestPolicy', args, _.spec, [
939-
{args: [{typeId: "4d810c9e-2d7f-11ef-b6f3-0fc90c99b135", optional: false, setoftype: false, variadic: false}, {typeId: "00000000-0000-0000-0000-0000000001ff", optional: false, setoftype: false, variadic: false}], returnTypeId: "50abdaa2-2d7f-11ef-92c5-bfd3f231be91", returnTypemod: "OptionalType"},
940-
]);
941-
return _.syntax.$expressionify({
942-
__kind__: $.ExpressionKind.Function,
943-
__element__: returnType,
944-
__cardinality__: cardinality,
945-
__name__: "default::latestPolicy",
946-
__args__: positionalArgs,
947-
__namedargs__: namedArgs,
948-
}) as any;
949-
};
950-
951925
type labelForUserλFuncExpr<
952926
P1 extends _.castMaps.orScalarLiteral<$.TypeSet<_std.$str>>,
953927
P2 extends $.TypeSet<$User>,
@@ -1026,6 +1000,33 @@ function tokenForUser(...args: any[]) {
10261000
}) as any;
10271001
};
10281002

1003+
type latestPolicyλFuncExpr<
1004+
P1 extends $.TypeSet<$Account>,
1005+
P2 extends _.castMaps.orScalarLiteral<$.TypeSet<_std.$number>>,
1006+
> = $.$expr_Function<
1007+
$Policy, $.cardutil.overrideLowerBound<$.cardutil.multiplyCardinalities<$.cardutil.paramCardinality<P1>, $.cardutil.paramCardinality<P2>>, 'Zero'>
1008+
>;
1009+
function latestPolicy<
1010+
P1 extends $.TypeSet<$Account>,
1011+
P2 extends _.castMaps.orScalarLiteral<$.TypeSet<_std.$number>>,
1012+
>(
1013+
account: P1,
1014+
key: P2,
1015+
): latestPolicyλFuncExpr<P1, P2>;
1016+
function latestPolicy(...args: any[]) {
1017+
const {returnType, cardinality, args: positionalArgs, namedArgs} = _.syntax.$resolveOverload('default::latestPolicy', args, _.spec, [
1018+
{args: [{typeId: "4d810c9e-2d7f-11ef-b6f3-0fc90c99b135", optional: false, setoftype: false, variadic: false}, {typeId: "00000000-0000-0000-0000-0000000001ff", optional: false, setoftype: false, variadic: false}], returnTypeId: "50abdaa2-2d7f-11ef-92c5-bfd3f231be91", returnTypemod: "OptionalType"},
1019+
]);
1020+
return _.syntax.$expressionify({
1021+
__kind__: $.ExpressionKind.Function,
1022+
__element__: returnType,
1023+
__cardinality__: cardinality,
1024+
__name__: "default::latestPolicy",
1025+
__args__: positionalArgs,
1026+
__namedargs__: namedArgs,
1027+
}) as any;
1028+
};
1029+
10291030
type tokenλFuncExpr<
10301031
P1 extends _.castMaps.orScalarLiteral<$.TypeSet<_std.$str>>,
10311032
> = $.$expr_Function<
@@ -1149,10 +1150,10 @@ type __defaultExports = {
11491150
"as_fixed": typeof as_fixed;
11501151
"is_member": typeof is_member;
11511152
"as_decimal": typeof as_decimal;
1152-
"latestPolicy": typeof latestPolicy;
11531153
"labelForUser": typeof labelForUser;
11541154
"label": typeof label;
11551155
"tokenForUser": typeof tokenForUser;
1156+
"latestPolicy": typeof latestPolicy;
11561157
"token": typeof token;
11571158
"global": typeof $default__globals
11581159
};
@@ -1221,10 +1222,10 @@ const __defaultExports: __defaultExports = {
12211222
"as_fixed": as_fixed,
12221223
"is_member": is_member,
12231224
"as_decimal": as_decimal,
1224-
"latestPolicy": latestPolicy,
12251225
"labelForUser": labelForUser,
12261226
"label": label,
12271227
"tokenForUser": tokenForUser,
1228+
"latestPolicy": latestPolicy,
12281229
"token": token,
12291230
"global": $default__globals
12301231
};

api/dbschema/interfaces.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,12 @@ export namespace $default {
8787
"implementation": string;
8888
"photo"?: string | null;
8989
"salt": string;
90-
"policies": Policy[];
91-
"approvers": Approver[];
9290
"messages": Message[];
9391
"proposals": Proposal[];
9492
"transactions": Transaction[];
9593
"transfers": Transfer[];
94+
"policies": Policy[];
95+
"approvers": Approver[];
9696
}
9797
export interface Action extends std.$Object {
9898
"functions": ActionFunction[];
@@ -210,8 +210,9 @@ export namespace $default {
210210
"proposal"?: Transaction | null;
211211
"initState": boolean;
212212
"isDraft": boolean;
213-
"latest"?: Policy | null;
213+
"latest"?: PolicyState | null;
214214
"isActive": boolean;
215+
"isLatest": boolean;
215216
}
216217
export interface Policy extends PolicyState {
217218
"approvers": Approver[];
@@ -310,8 +311,8 @@ export namespace $default {
310311
export interface User extends std.$Object {
311312
"primaryAccount"?: Account | null;
312313
"approvers": Approver[];
313-
"accounts": Account[];
314314
"contacts": Contact[];
315+
"accounts": Account[];
315316
}
316317
export interface current_approver extends Approver {}
317318
export interface current_user extends User {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
CREATE MIGRATION m1msez63jkpjpwsku7jrbuu45dovo5hylpmgeylgdlt3temlkyvn7q
2+
ONTO m1flrdckmwin6sg42mvtplf7qh2l6z2kv3bkmutql23bffpz3zdlgq
3+
{
4+
ALTER TYPE default::PolicyState {
5+
CREATE REQUIRED PROPERTY isLatest: std::bool {
6+
SET default := false;
7+
};
8+
};
9+
ALTER FUNCTION default::latestPolicy(account: default::Account, key: std::int64) USING (std::assert_single((SELECT
10+
default::Policy
11+
FILTER
12+
(((.account = account) AND (.key = key)) AND .isLatest)
13+
)));
14+
ALTER TYPE default::PolicyState {
15+
ALTER LINK latest {
16+
USING ((__source__ IF .isLatest ELSE default::latestPolicy(.account, .key)));
17+
};
18+
ALTER PROPERTY isLatest {
19+
CREATE REWRITE
20+
INSERT
21+
USING ((((.activationBlock ?? 0n) > (((SELECT
22+
default::latestPolicy(.account, .key)
23+
)).activationBlock ?? -1n)) IF NOT (__specified__.isLatest) ELSE .isLatest));
24+
};
25+
CREATE INDEX ON ((.account, .key, .isLatest));
26+
CREATE INDEX ON ((.account, .isLatest));
27+
ALTER PROPERTY isActive {
28+
USING ((.isLatest AND .hasBeenActive));
29+
};
30+
};
31+
ALTER TYPE default::Policy {
32+
ALTER TRIGGER update_proposals_when_deleted USING (UPDATE
33+
default::Proposal
34+
FILTER
35+
(((.account = __old__.account) AND (.policy.key = __old__.key)) AND (([IS default::Transaction].status ?= default::TransactionStatus.Pending) OR (EXISTS ([IS default::Message].id) AND NOT (EXISTS ([IS default::Message].signature)))))
36+
SET {
37+
policy := (SELECT
38+
default::Policy FILTER
39+
(.account = __old__.account)
40+
ORDER BY
41+
.isActive ASC
42+
LIMIT
43+
1
44+
)
45+
});
46+
};
47+
ALTER TYPE default::RemovedPolicy {
48+
CREATE TRIGGER update_proposals_when_latest
49+
AFTER UPDATE, INSERT
50+
FOR EACH
51+
WHEN (__new__.isLatest)
52+
DO (UPDATE
53+
default::Proposal
54+
FILTER
55+
(((.account = __new__.account) AND (.policy.key = __new__.key)) AND (([IS default::Transaction].status ?= default::TransactionStatus.Pending) OR (EXISTS ([IS default::Message].id) AND NOT (EXISTS ([IS default::Message].signature)))))
56+
SET {
57+
policy := (SELECT
58+
default::Policy FILTER
59+
(.account = __new__.account)
60+
ORDER BY
61+
.isActive ASC
62+
LIMIT
63+
1
64+
)
65+
});
66+
};
67+
ALTER TYPE default::Policy {
68+
ALTER TRIGGER update_proposals RENAME TO update_proposals_when_latest;
69+
};
70+
ALTER TYPE default::Policy {
71+
DROP TRIGGER link_insert;
72+
ALTER TRIGGER update_proposals_when_latest WHEN (__new__.isLatest);
73+
};
74+
ALTER TYPE default::RemovedPolicy {
75+
DROP TRIGGER rm_policy_draft_link;
76+
DROP TRIGGER update_proposals;
77+
};
78+
ALTER TYPE default::Account {
79+
ALTER LINK policies {
80+
USING (SELECT
81+
.<account[IS default::Policy]
82+
FILTER
83+
.isLatest
84+
);
85+
RESET ON SOURCE DELETE;
86+
RESET ON TARGET DELETE;
87+
};
88+
};
89+
# Migrate PolicyState with new isLatest property
90+
# Latest PolicyState is the one with the highest activationBlock
91+
update PolicyState set {
92+
isLatest := (
93+
with id := .id,
94+
account := .account,
95+
key := .key,
96+
latest := (select detached PolicyState filter .account = account and .key = key order by .activationBlock desc limit 1)
97+
select (id ?= latest.id)
98+
)
99+
};
100+
};

api/dbschema/policy.esdl

+21-26
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,27 @@ module default {
88
on target delete delete source;
99
}
1010
activationBlock: bigint { constraint min_value(0n); }
11-
required property initState := (.activationBlock ?= 0);
12-
required property hasBeenActive := exists .activationBlock;
13-
latest := latestPolicy(.account, .key);
11+
required isLatest: bool {
12+
default := false;
13+
rewrite insert using (
14+
((.activationBlock ?? 0n) > ((select latestPolicy(.account, .key)).activationBlock ?? -1n))
15+
if (not __specified__.isLatest) else .isLatest
16+
)
17+
}
18+
required initState := .activationBlock ?= 0;
19+
required hasBeenActive := exists .activationBlock;
20+
required isActive := .isLatest and .hasBeenActive;
21+
required isDraft := exists .draft;
22+
latest := (__source__ if .isLatest else latestPolicy(.account, .key));
1423
draft := assert_single((
1524
with account := __source__.account, key := __source__.key
1625
select detached PolicyState filter .account = account and .key = key and not .hasBeenActive
1726
order by .createdAt desc limit 1
1827
));
19-
required property isActive := (.hasBeenActive and .latest ?= __source__);
20-
required property isDraft := exists .draft;
2128

2229
index on ((.account, .key));
30+
index on ((.account, .key, .isLatest));
31+
index on ((.account, .isLatest));
2332

2433
access policy members_select_insert_update allow select, insert, update
2534
using (is_member(.account));
@@ -37,15 +46,8 @@ module default {
3746
required allowMessages: bool { default := false; }
3847
required delay: uint32 { default := 0; }
3948

40-
trigger link_insert after insert, update for each
41-
when ((__new__.activationBlock ?? 0) > ((select __new__.account.policies filter .key = __new__.key limit 1).activationBlock ?? -1)) do (
42-
update __new__.account set {
43-
policies := assert_distinct((select __new__.account.policies filter .key != __new__.key) union __new__)
44-
}
45-
);
46-
47-
trigger update_proposals after insert, update for each
48-
when ((__new__.activationBlock ?? 0) > ((select __new__.account.policies filter .key = __new__.key limit 1).activationBlock ?? -1)) do (
49+
trigger update_proposals_when_latest after insert, update for each
50+
when (__new__.isLatest) do (
4951
update Proposal filter .account = __new__.account and .policy.key = __new__.key and
5052
(([is Transaction].status ?= TransactionStatus.Pending) or ((exists [is Message].id) and (not exists [is Message].signature)))
5153
set {
@@ -57,31 +59,24 @@ module default {
5759
update Proposal filter .account = __old__.account and .policy.key = __old__.key and
5860
(([is Transaction].status ?= TransactionStatus.Pending) or ((exists [is Message].id) and (not exists [is Message].signature)))
5961
set {
60-
policy := (select __old__.account.policies limit 1)
62+
policy := (select Policy filter .account = __old__.account order by .isActive limit 1)
6163
}
6264
)
6365
}
6466

6567
type RemovedPolicy extending PolicyState {
66-
trigger rm_policy_draft_link after insert, update for each
67-
when ((__new__.activationBlock ?? 0) > ((select __new__.account.policies filter .key = __new__.key limit 1).activationBlock ?? -1)) do (
68-
update __new__.account set {
69-
policies := assert_distinct((select __new__.account.policies filter .key != __new__.key))
70-
}
71-
);
72-
73-
trigger update_proposals after insert, update for each
74-
when ((__new__.activationBlock ?? 0) > ((select __new__.account.policies filter .key = __new__.key limit 1).activationBlock ?? -1)) do (
68+
trigger update_proposals_when_latest after insert, update for each
69+
when (__new__.isLatest) do (
7570
update Proposal filter .account = __new__.account and .policy.key = __new__.key and
7671
(([is Transaction].status ?= TransactionStatus.Pending) or ((exists [is Message].id) and (not exists [is Message].signature)))
7772
set {
78-
policy := (select __new__.account.policies limit 1)
73+
policy := (select Policy filter .account = __new__.account order by .isActive limit 1)
7974
}
8075
);
8176
}
8277

8378
function latestPolicy(account: Account, key: int64) -> optional Policy using (
84-
assert_single((select account.policies filter .key = key))
79+
assert_single((select Policy filter .account = account and .key = key and .isLatest))
8580
);
8681

8782
type Action {

0 commit comments

Comments
 (0)