-
Notifications
You must be signed in to change notification settings - Fork 0
/
schema.sql
176 lines (155 loc) · 4.47 KB
/
schema.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
-- TODO: synthetic ids to reduce storage
do $SCHEMA$
declare
settings_table_exists bool;
begin
settings_table_exists := (select exists ( SELECT 1
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
-- WHERE n.nspname = 'schema_name'
AND c.relname = 'settings'
AND c.relkind = 'r' -- only tables
));
-- if false and settings_table_exists then
if settings_table_exists then
if (select schema_version from settings) = 32 then
return;
end if;
end if;
drop function if exists get_address_txs(address text);
drop view if exists address_tx;
drop view if exists tx_view;
drop view if exists sent_by_address;
drop view if exists received_by_address;
drop trigger if exists vin_delete on vin;
drop function if exists vin_delete();
drop trigger if exists vin_insert on vin;
drop function if exists vin_insert();
drop table if exists vout;
drop table if exists vin;
drop table if exists tx;
drop table if exists block;
drop table if exists settings;
create table settings (
schema_version int not null default(32)
);
insert into settings default values;
create table block (
hash text primary key,
blindhash text,
height int not null check (height >= 0),
time timestamptz not null
);
create table tx (
tx_id text primary key,
hash text not null unique,
block_hash text not null references block(hash) on delete cascade,
n int not null,
locktime int not null,
version int not null,
unique (block_hash, n)
);
create table vin (
tx_id text not null references tx(tx_id) on delete cascade,
n int check(n >= 0),
coinbase text,
prev_tx_id text,
vout int,
script_sig jsonb,
value numeric,
address text,
primary key (tx_id, n),
check ((
coinbase is null and
prev_tx_id is not null and
vout is not null
) or (
coinbase is not null and
prev_tx_id is null and
vout is null
))
);
create table vout (
tx_id text not null references tx(tx_id) on delete cascade,
n int check(n >= 0),
script_pub_key jsonb,
value numeric not null,
spending_tx_id text,
spending_n int
);
create function vin_insert() returns trigger as $$
begin
if new.tx_id is not null then
select
value,
(jsonb_array_elements(vout.script_pub_key->'addresses')->>0)::text address
from vout
into new.value, new.address
where vout.tx_id = new.prev_tx_id and vout.n = new.vout;
-- Mark output as spent
update vout
set spending_tx_id = new.tx_id, spending_n = new.n
where vout.tx_id = new.prev_tx_id and vout.n = new.vout;
end if;
return new;
end; $$ language plpgsql;
create trigger vin_insert
before insert on vin
for each row
execute procedure vin_insert();
create function vin_delete() returns trigger as $$
begin
if old.tx_id is not null then
-- Mark output as no longer spent
update vout
set spending_tx_id = null, spending_n = null
where vout.tx_id = old.prev_tx_id and vout.n = old.vout;
end if;
return old;
end; $$ language plpgsql;
create trigger vin_delete
before delete on vin
for each row
execute procedure vin_delete();
create view received_by_address as
select
vout.tx_id,
vout.n,
vout.value,
(jsonb_array_elements(vout.script_pub_key->'addresses')->>0)::text address,
block.time
from vout
inner join tx on tx.tx_id = vout.tx_id
inner join block on block.hash = tx.block_hash
where
vout.script_pub_key is not null and
vout.script_pub_key->'addresses' is not null;
create view sent_by_address as
select vin.*, block.time
from vin
inner join tx on tx.tx_id = vin.tx_id
inner join block on block.hash = tx.block_hash
where vin.address is not null;
create view tx_view as
select tx.*, block.time
from tx
inner join block on block.hash = tx.block_hash;
create view address_tx as
select tx.*, t.address, t.time
from
(
select tx_id, time, address
from received_by_address
union
select tx_id, time, address
from sent_by_address
) t
inner join tx on tx.tx_id = t.tx_id;
create function get_address_txs(_address text) returns setof tx as $$
select tx.*
from address_tx
inner join tx on tx.tx_id = address_tx.tx_id
where address_tx.address = _address
order by address_tx.time desc, tx.n asc;
$$ language sql stable;
end; $SCHEMA$ language plpgsql;