-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBlockHeader.cs
More file actions
157 lines (138 loc) · 3.9 KB
/
BlockHeader.cs
File metadata and controls
157 lines (138 loc) · 3.9 KB
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
using BitcoinKernel.Core.Exceptions;
using BitcoinKernel.Interop;
namespace BitcoinKernel.Core.Abstractions;
/// <summary>
/// Represents a block header containing metadata about a block.
/// </summary>
public sealed class BlockHeader : IDisposable
{
private IntPtr _handle;
private bool _disposed;
private readonly bool _ownsHandle;
internal BlockHeader(IntPtr handle, bool ownsHandle = true)
{
_handle = handle != IntPtr.Zero
? handle
: throw new ArgumentException("Invalid block header handle", nameof(handle));
_ownsHandle = ownsHandle;
}
/// <summary>
/// Creates a block header from raw serialized data (80 bytes).
/// </summary>
public static BlockHeader FromBytes(byte[] rawHeaderData)
{
ArgumentNullException.ThrowIfNull(rawHeaderData, nameof(rawHeaderData));
if (rawHeaderData.Length != 80)
throw new ArgumentException("Block header must be exactly 80 bytes", nameof(rawHeaderData));
IntPtr headerPtr = NativeMethods.BlockHeaderCreate(rawHeaderData, (UIntPtr)rawHeaderData.Length);
if (headerPtr == IntPtr.Zero)
{
throw new BlockException("Failed to create block header from raw data");
}
return new BlockHeader(headerPtr);
}
internal IntPtr Handle
{
get
{
ThrowIfDisposed();
return _handle;
}
}
/// <summary>
/// Gets the block hash of this header.
/// </summary>
public byte[] GetHash()
{
ThrowIfDisposed();
var hashPtr = NativeMethods.BlockHeaderGetHash(_handle);
if (hashPtr == IntPtr.Zero)
{
throw new BlockException("Failed to get block hash from header");
}
using var blockHash = new BlockHash(hashPtr);
return blockHash.ToBytes();
}
/// <summary>
/// Gets the previous block hash from this header.
/// </summary>
public byte[] GetPrevHash()
{
ThrowIfDisposed();
var hashPtr = NativeMethods.BlockHeaderGetPrevHash(_handle);
if (hashPtr == IntPtr.Zero)
{
throw new BlockException("Failed to get previous block hash from header");
}
// The hash pointer is unowned and only valid for the lifetime of the header
var bytes = new byte[32];
NativeMethods.BlockHashToBytes(hashPtr, bytes);
return bytes;
}
/// <summary>
/// Gets the timestamp from this header (Unix epoch seconds).
/// </summary>
public uint Timestamp
{
get
{
ThrowIfDisposed();
return NativeMethods.BlockHeaderGetTimestamp(_handle);
}
}
/// <summary>
/// Gets the nBits difficulty target from this header (compact format).
/// </summary>
public uint Bits
{
get
{
ThrowIfDisposed();
return NativeMethods.BlockHeaderGetBits(_handle);
}
}
/// <summary>
/// Gets the version from this header.
/// </summary>
public int Version
{
get
{
ThrowIfDisposed();
return NativeMethods.BlockHeaderGetVersion(_handle);
}
}
/// <summary>
/// Gets the nonce from this header.
/// </summary>
public uint Nonce
{
get
{
ThrowIfDisposed();
return NativeMethods.BlockHeaderGetNonce(_handle);
}
}
private void ThrowIfDisposed()
{
if (_disposed)
throw new ObjectDisposedException(nameof(BlockHeader));
}
public void Dispose()
{
if (!_disposed)
{
if (_handle != IntPtr.Zero && _ownsHandle)
{
NativeMethods.BlockHeaderDestroy(_handle);
_handle = IntPtr.Zero;
}
_disposed = true;
}
}
~BlockHeader()
{
if (_ownsHandle)
Dispose();
}
}