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/>.
17 from .varlen import varlenDecode, varlenEncode
18 from util import dblsha
19 from struct import pack, unpack
21 _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'
24 def __init__(self, data=None):
38 def setCoinbase(self, sigScript, seqno = 0xffffffff, height = None):
39 if not height is None:
40 sigScript = pack('<BL', 4, height) + sigScript
41 self.inputs = ( ((_nullprev, 0xffffffff), sigScript, seqno), )
43 def addInput(self, prevout, sigScript, seqno = 0xffffffff):
44 self.inputs.append( (prevout, sigScript, seqno) )
46 def addOutput(self, amount, pkScript):
47 self.outputs.append( (amount, pkScript) )
49 def disassemble(self, retExtra = False):
50 self.version = unpack('<L', self.data[:4])[0]
53 (inputCount, data) = varlenDecode(self.data[4:], rc)
55 for i in range(inputCount):
56 prevout = (data[:32], unpack('<L', data[32:36])[0])
58 (sigScriptLen, data) = varlenDecode(data[36:], rc)
59 sigScript = data[:sigScriptLen]
60 seqno = unpack('<L', data[sigScriptLen:sigScriptLen + 4])[0]
61 data = data[sigScriptLen + 4:]
62 rc[0] += sigScriptLen + 4
63 inputs.append( (prevout, sigScript, seqno) )
66 (outputCount, data) = varlenDecode(data, rc)
68 for i in range(outputCount):
69 amount = unpack('<Q', data[:8])[0]
71 (pkScriptLen, data) = varlenDecode(data[8:], rc)
72 pkScript = data[:pkScriptLen]
73 data = data[pkScriptLen:]
75 outputs.append( (amount, pkScript) )
76 self.outputs = outputs
78 self.locktime = unpack('<L', data[:4])[0]
82 assert data == self.data[rc[0]:]
85 self.data = self.data[:rc[0]]
89 return len(self.inputs) == 1 and self.inputs[0][0] == (_nullprev, 0xffffffff)
91 def getCoinbase(self):
92 return self.inputs[0][1]
95 data = pack('<L', self.version)
98 data += varlenEncode(len(inputs))
99 for prevout, sigScript, seqno in inputs:
100 data += prevout[0] + pack('<L', prevout[1])
101 data += varlenEncode(len(sigScript)) + sigScript
102 data += pack('<L', seqno)
104 outputs = self.outputs
105 data += varlenEncode(len(outputs))
106 for amount, pkScript in outputs:
107 data += pack('<Q', amount)
108 data += varlenEncode(len(pkScript)) + pkScript
110 data += pack('<L', self.locktime)
116 self.txid = dblsha(self.data)
120 d = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00'
122 assert t.txid == b"C\xeczW\x9fUa\xa4*~\x967\xadAVg'5\xa6X\xbe'R\x18\x18\x01\xf7#\xba3\x16\xd2"
126 assert not t.isCoinbase()
128 t.addInput((b' '*32, 0), b'INPUT')
129 t.addOutput(0x10000, b'OUTPUT')
131 assert t.txid == b'>`\x97\xecu\x8e\xb5\xef\x19k\x17d\x96sw\xb1\xf1\x9bO\x1c6\xa0\xbe\xf7N\xed\x13j\xfdHF\x1a'
134 assert t.txid == b'>`\x97\xecu\x8e\xb5\xef\x19k\x17d\x96sw\xb1\xf1\x9bO\x1c6\xa0\xbe\xf7N\xed\x13j\xfdHF\x1a'
135 assert not t.isCoinbase()
137 t.setCoinbase(b'COINBASE')
138 t.addOutput(0x10000, b'OUTPUT')
139 assert t.isCoinbase()
140 assert t.getCoinbase() == b'COINBASE'
142 assert t.txid == b'n\xb9\xdc\xef\xe9\xdb(R\x8dC~-\xef~\x88d\x15+X\x13&\xb7\xbc$\xb1h\xf3g=\x9b~V'