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;