1 # Eloipool - Python Bitcoin pool server
2 # Copyright (C) 2011-2012 Luke Dashjr <luke-jr+eloipool@utopios.org>
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as
6 # published by the Free Software Foundation, either version 3 of the
7 # License, or (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 from .varlen import varlenDecode, varlenEncode
19 from util import dblsha
20 from struct import pack, unpack
22 _nullprev = b'\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
25 def __init__(self, data=None):
39 def setCoinbase(self, sigScript, seqno = 0xffffffff, height = None):
40 if not height is None:
41 # NOTE: This is required to be the minimum valid length by BIP 34
42 sigScript = bitcoin.script.encodeUNum(height) + sigScript
43 self.inputs = ( ((_nullprev, 0xffffffff), sigScript, seqno), )
45 def addInput(self, prevout, sigScript, seqno = 0xffffffff):
46 self.inputs.append( (prevout, sigScript, seqno) )
48 def addOutput(self, amount, pkScript):
49 self.outputs.append( (amount, pkScript) )
51 def disassemble(self, retExtra = False):
52 self.version = unpack('<L', self.data[:4])[0]
55 (inputCount, data) = varlenDecode(self.data[4:], rc)
57 for i in range(inputCount):
58 prevout = (data[:32], unpack('<L', data[32:36])[0])
60 (sigScriptLen, data) = varlenDecode(data[36:], rc)
61 sigScript = data[:sigScriptLen]
62 seqno = unpack('<L', data[sigScriptLen:sigScriptLen + 4])[0]
63 data = data[sigScriptLen + 4:]
64 rc[0] += sigScriptLen + 4
65 inputs.append( (prevout, sigScript, seqno) )
68 (outputCount, data) = varlenDecode(data, rc)
70 for i in range(outputCount):
71 amount = unpack('<Q', data[:8])[0]
73 (pkScriptLen, data) = varlenDecode(data[8:], rc)
74 pkScript = data[:pkScriptLen]
75 data = data[pkScriptLen:]
77 outputs.append( (amount, pkScript) )
78 self.outputs = outputs
80 self.locktime = unpack('<L', data[:4])[0]
84 assert data == self.data[rc[0]:]
87 self.data = self.data[:rc[0]]
91 return len(self.inputs) == 1 and self.inputs[0][0] == (_nullprev, 0xffffffff)
93 def getCoinbase(self):
94 return self.inputs[0][1]
97 data = pack('<L', self.version)
100 data += varlenEncode(len(inputs))
101 for prevout, sigScript, seqno in inputs:
102 data += prevout[0] + pack('<L', prevout[1])
103 data += varlenEncode(len(sigScript)) + sigScript
104 data += pack('<L', seqno)
106 outputs = self.outputs
107 data += varlenEncode(len(outputs))
108 for amount, pkScript in outputs:
109 data += pack('<Q', amount)
110 data += varlenEncode(len(pkScript)) + pkScript
112 data += pack('<L', self.locktime)
118 self.txid = dblsha(self.data)
122 d = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00'
124 assert t.txid == b"C\xeczW\x9fUa\xa4*~\x967\xadAVg'5\xa6X\xbe'R\x18\x18\x01\xf7#\xba3\x16\xd2"
128 assert not t.isCoinbase()
130 t.addInput((b' '*32, 0), b'INPUT')
131 t.addOutput(0x10000, b'OUTPUT')
133 assert t.txid == b'>`\x97\xecu\x8e\xb5\xef\x19k\x17d\x96sw\xb1\xf1\x9bO\x1c6\xa0\xbe\xf7N\xed\x13j\xfdHF\x1a'
136 assert t.txid == b'>`\x97\xecu\x8e\xb5\xef\x19k\x17d\x96sw\xb1\xf1\x9bO\x1c6\xa0\xbe\xf7N\xed\x13j\xfdHF\x1a'
137 assert not t.isCoinbase()
139 t.setCoinbase(b'COINBASE')
140 t.addOutput(0x10000, b'OUTPUT')
141 assert t.isCoinbase()
142 assert t.getCoinbase() == b'COINBASE'
144 assert t.txid == b'n\xb9\xdc\xef\xe9\xdb(R\x8dC~-\xef~\x88d\x15+X\x13&\xb7\xbc$\xb1h\xf3g=\x9b~V'