File : transactions.adb
1 with Ada.IO_Exceptions; use Ada.IO_Exceptions;
2 with VarInts; use VarInts;
3 with Hash_Streams;
4
5 package body Transactions is
6
7 package body Traditional is
8
9 -- Read a Traditional representation of a Tx into its Fast Form
10 procedure TradTx_Read(Stream : not null access Root_Stream_Type'Class;
11 T : out Tx) is
12 -- We hash the TX as it is read:
13 package HashStream is new Hash_Streams;
14 HS : aliased HashStream.Hash_Stream(HashStream.Stream_Access(Stream));
15 HSA : constant HashStream.Hash_Stream_Access := HS'Access;
16 --
17 Scr_Len : Scripts_Bounds; -- for reading script lengths
18 -- current top of scriptolade
19 Scr_Top : Scriptolade_Bounds := Scriptolade_Bounds'First;
20 -- Corrupt Tx will often give nonsensical counts, we'll trap'em
21 Ins_Count : Positive range 1 .. T.Inp_Slots;
22 Outs_Count : Positive range 1 .. T.Out_Slots;
23 begin
24 -- Read version
25 Integer_32'Read(HSA, T.Version);
26 ----------------------------------------------------------------
27 -- Read count of inputs
28 VarInt'Read(HSA, VarInt(Ins_Count));
29 -- Read inputs
30 for I in T.Inputs'First .. Ins_Count loop
31 -- Read PrevOut
32 OutPoint'Read(HSA, T.Inputs(I).PreviousOutput);
33 -- Save current scriptolade top as this script's offset
34 T.Inputs(I).SignatureScript.Offset := Scr_Top;
35 -- Read script length
36 VarInt'Read(HSA, VarInt(Scr_Len));
37 -- Read script
38 for N in Scr_Top .. Scr_Top + Scr_Len - 1 loop
39 Unsigned_8'Read(HSA, T.Scripts(N));
40 end loop;
41 -- Get the new scriptolade top
42 Scr_Top := Scr_Top + Scr_Len;
43 -- Save the script length
44 T.Inputs(I).SignatureScript.Length := Scr_Len;
45 -- Read the sequence number
46 Unsigned_32'Read(HSA, T.Inputs(I).Sequence);
47 end loop;
48 -- Save the input count
49 T.Frame.N_Ins := Ins_Count;
50 ----------------------------------------------------------------
51 -- Read count of outputs
52 VarInt'Read(HSA, VarInt(Outs_Count));
53 -- Read outputs
54 for O in T.Outputs'First .. Outs_Count loop
55 -- Read the Value
56 Unsigned_64'Read(HSA, T.Outputs(O).Value);
57 -- Save current scriptolade top as this script's offset
58 T.Outputs(O).PkScript.Offset := Scr_Top;
59 -- Read script length
60 VarInt'Read(HSA, VarInt(Scr_Len));
61 -- Read script.
62 for N in Scr_Top .. Scr_Top + Scr_Len - 1 loop
63 Unsigned_8'Read(HSA, T.Scripts(N));
64 end loop;
65 -- Get the new scriptolade top
66 Scr_Top := Scr_Top + Scr_Len;
67 -- Save the script length
68 T.Outputs(O).PkScript.Length := Scr_Len;
69 end loop;
70 -- Save the output count
71 T.Frame.N_Outs := Outs_Count;
72 ----------------------------------------------------------------
73 -- Read the locktime
74 Unsigned_32'Read(HSA, T.LockTime);
75 -- Save tx hash
76 T.Hash := HashStream.GetDoubleHash(HS);
77 T.NBytes := Unsigned_32(HashStream.GetCount(HS));
78 exception
79 when End_Error =>
80 raise TradTxNotRead with "Procrusted";
81 when Constraint_Error =>
82 raise TradTxNotRead with "Corrupt";
83 when others =>
84 raise TradTxNotRead with "Unknown";
85 end TradTx_Read;
86
87
88 -- Produce a Traditional representation of a Tx from its Fast Form
89 procedure TradTx_Write(Stream : not null access Root_Stream_Type'Class;
90 T : in Tx) is
91 begin
92 -- Write version
93 Integer_32'Write(Stream, T.Version);
94 ----------------------------------------------------------------
95 -- Write count of inputs
96 VarInt'Write(Stream, VarInt(T.Frame.N_Ins));
97 -- Write the inputs
98 for I in T.Inputs'First .. T.Frame.N_Ins loop
99 -- Write PrevOut
100 OutPoint'Write(Stream, T.Inputs(I).PreviousOutput);
101 -- Now to write the script:
102 declare -- breaking it down for clarity:
103 -- Length of this script
104 Scr_Len : constant Scripts_Bounds
105 := T.Inputs(I).SignatureScript.Length;
106 -- Where in scriptolade to look for it:
107 Scr_Offset : constant Scriptolade_Bounds
108 := T.Inputs(I).SignatureScript.Offset;
109 begin
110 -- Write script length
111 VarInt'Write(Stream, VarInt(Scr_Len));
112 -- Write the script itself
113 for N in Scr_Offset .. Scr_Offset + Scr_Len - 1 loop
114 Unsigned_8'Write(Stream, T.Scripts(N));
115 end loop;
116 end;
117 -- Write sequence number
118 Unsigned_32'Write(Stream, T.Inputs(I).Sequence);
119 end loop;
120 ----------------------------------------------------------------
121 -- Write count of outputs
122 VarInt'Write(Stream, VarInt(T.Frame.N_Outs));
123 -- Write the outputs
124 for O in T.Outputs'First .. T.Frame.N_Outs loop
125 -- Write the Value
126 Unsigned_64'Write(Stream, T.Outputs(O).Value);
127 -- Now to write the script:
128 declare -- breaking it down for clarity:
129 -- Length of this script
130 Scr_Len : constant Scripts_Bounds
131 := T.Outputs(O).PkScript.Length;
132 -- Where in scriptolade to look for it:
133 Scr_Offset : constant Scriptolade_Bounds
134 := T.Outputs(O).PkScript.Offset;
135 begin
136 -- Write script length
137 VarInt'Write(Stream, VarInt(Scr_Len));
138 -- Write script
139 for N in Scr_Offset .. Scr_Offset + Scr_Len - 1 loop
140 Unsigned_8'Write(Stream, T.Scripts(N));
141 end loop;
142 end;
143 end loop;
144 ----------------------------------------------------------------
145 -- Write the locktime
146 Unsigned_32'Write(Stream, T.LockTime);
147 exception
148 when others =>
149 raise TradTxNotWritten with "Failed";
150 end TradTx_Write;
151
152 end Traditional;
153
154 end Transactions;