Ejemplo n.º 1
0
    void writeHeader(const String& name, uint8_t msgtype, uint32_t seqid) {
      writeUByte(PROTOCOL_ID);
      writeUByte(version | (msgtype << TYPE_SHIFT_AMOUNT));
      writeVarint(seqid);
      writeString(name);

      state = STATE_VALUE_WRITE;
    }
bool BinaryOutputStreamSerializer::operator()(uint64_t& value, Common::StringView name) {
  writeVarint(stream, value);
  return true;
}
bool BinaryOutputStreamSerializer::operator()(std::string& value, Common::StringView name) {
  writeVarint(stream, value.size());
  checkedWrite(value.data(), value.size());
  return true;
}
bool BinaryOutputStreamSerializer::beginArray(size_t& size, Common::StringView name) {
  writeVarint(stream, size);
  return true;
}
bool BinaryOutputStreamSerializer::operator()(int64_t& value, Common::StringView name) {
  writeVarint(stream, static_cast<uint64_t>(value));
  return true;
}
int main(int argc, char **argv) {
	dongleHandle dongle = NULL;
	unsigned char in[260];
	unsigned char out[260];
	int result;
	int sw;
	int apduSize;		
	uint32_t signingIndex;
	unsigned char newTransaction;
	bitcoinTransaction **transactions = NULL;
	prevout *prevouts = NULL;
	int transactionsNumber = 0;
	int status = 0;
	int i;

	initDongle();
	if (argc < 5) {
		fprintf(stderr, "Usage : %s [NEW for a new transaction|CONTINUE to keep on signing inputs in a previous transaction] [index of input to sign] [redeem script to use or empty to use the default one] [list of transactions output to use in this transaction]\n", argv[0]);
		fprintf(stderr, "Transaction outputs are coded as [hex transaction:output index] to generate a trusted input, or [-hex transaction:output index] to use the prevout directly for an output you don't own (relaxed wallet mode)\n");		
		goto cleanup;
	}
	if (strcasecmp(argv[1], "new") == 0) {
		newTransaction = 0x01;
	}
	else
	if (strcasecmp(argv[1], "continue") == 0) {
		newTransaction = 0x00;
	}
	else {
		fprintf(stderr, "Invalid transaction usage %s\n", argv[1]);
		goto cleanup;
	}
	result = strtol(argv[2], NULL, 10);
	if (result < 0) {
		fprintf(stderr, "Invalid input to sign index\n");
		goto cleanup;
	}
	signingIndex = result;
	transactionsNumber = argc - 1 - 3;
	transactions = (bitcoinTransaction**)malloc(sizeof(bitcoinTransaction*) * transactionsNumber);
	if (transactions == NULL) {
		fprintf(stderr, "Couldn't allocate transactions list\n");
		goto cleanup;
	}
	for (i=0; i<transactionsNumber; i++) {
		transactions[i] = NULL;
	}
	prevouts = (prevout*)malloc(sizeof(prevout) * transactionsNumber);
	if (prevouts == NULL) {
		fprintf(stderr, "Couldn't allocate prevouts list\n");
		goto cleanup;
	}
	dongle = getFirstDongle();
	if (dongle == NULL) {
		fprintf(stderr, "No dongle found\n");
		return 0;
	}	
	// Parse each provided transaction, get the associated trusted input when necessary
	for (i=0; i<transactionsNumber; i++) {
		uint32_t index;
		unsigned char untrusted;
		untrusted = (argv[4 + i][0] == '-');
		transactions[i] = parseTransactionStringWithIndex(argv[4 + i] + (untrusted ? 1 : 0), &index);
		if (transactions[i] == NULL) {
			fprintf(stderr, "Invalid transaction %d\n", i + 1);
			goto cleanup;
		}
		if (untrusted) {
			fprintf(stderr, "Untrusted mode not supported\n");
			goto cleanup;
		}
		else {
			result = getTrustedInput(dongle, transactions[i], index, prevouts[i].prevout, sizeof(prevouts[i].prevout));
			if (result < 0) {
				fprintf(stderr, "Error getting trusted input %d\n", i + 1);
				goto cleanup;
			}
			prevouts[i].isTrusted = 1;
			printf("Trusted input #%d\n", (i + 1));
			displayBinary(prevouts[i].prevout, result);
		}
		prevouts[i].outputIndex = index;
	}
	// Then start building a fake transaction with the inputs we want
	apduSize = 0;
	in[apduSize++] = BTCHIP_CLA;
	in[apduSize++] = BTCHIP_INS_HASH_INPUT_START;
	in[apduSize++] = 0x00;
	in[apduSize++] = (newTransaction ? 0x00 : 0x80);
	in[apduSize++] = 0x00;
	memcpy(in + apduSize, DEFAULT_VERSION, sizeof(DEFAULT_VERSION));
	apduSize += sizeof(DEFAULT_VERSION);
	apduSize += writeVarint(transactionsNumber, (in + apduSize), (sizeof(in) - apduSize));
	in[OFFSET_CDATA] = (apduSize - 5);
	result = sendApduDongle(dongle, in, apduSize, out, sizeof(out), &sw);
	if (result < 0) {
		fprintf(stderr, "I/O error\n");
		return 0;
	}
	if (sw != SW_OK) {
		fprintf(stderr, "Dongle application error : %.4x\n", sw);
		return 0;
	}
	// Each input
	for (i=0; i<transactionsNumber; i++) {
		int scriptLength;
		unsigned char *script;			
		apduSize = 0;
		in[apduSize++] = BTCHIP_CLA;
		in[apduSize++] = BTCHIP_INS_HASH_INPUT_START;
		in[apduSize++] = 0x80;
		in[apduSize++] = 0x00;
		in[apduSize++] = 0x00;
		if (prevouts[i].isTrusted) {
			in[apduSize++] = 0x01;
			in[apduSize++] = sizeof(prevouts[i].prevout);
			memcpy(in + apduSize, prevouts[i].prevout, sizeof(prevouts[i].prevout));
			apduSize += sizeof(prevouts[i].prevout);
		}
		else {
			in[apduSize++] = 0x00;
			in[apduSize++] = PREVOUT_SIZE;
			memcpy(in + apduSize, prevouts[i].prevout, PREVOUT_SIZE);
			apduSize += PREVOUT_SIZE;
		}
		// Get the script length - use either the output script if signing the current index
		// Or a null script
		if (i == signingIndex) {
			if (strlen(argv[3]) != 0) {
				scriptLength = strlen(argv[3]) / 2;
				script = (unsigned char*)malloc(scriptLength);
				if (script == NULL) {
					fprintf(stderr, "Failed to allocate script\n");
					goto cleanup;
				}
				scriptLength = hexToBin(argv[3], script, scriptLength);
				if (scriptLength <= 0) {
					free(script);
					fprintf(stderr, "Invalid redeem script\n");
					goto cleanup;
				}
			}
			else {
				int j;
				bitcoinOutput *output = transactions[i]->outputs;
				for (j=0; j<prevouts[i].outputIndex; j++) {
					output = output->next;
				}
				scriptLength = output->scriptLength;
				script = output->script;
			}
		}
		else {
			scriptLength = 0;
			script = NULL;
		}
		apduSize += writeVarint(scriptLength, (in + apduSize), (sizeof(in) - apduSize));
		if (scriptLength != 0) {
			memcpy(in + apduSize, script, scriptLength);
			apduSize += scriptLength;
		}
		if (strlen(argv[3]) != 0) {
			free(script);
		}
		memcpy(in + apduSize, DEFAULT_SEQUENCE, sizeof(DEFAULT_SEQUENCE));
		apduSize += sizeof(DEFAULT_SEQUENCE);
		in[OFFSET_CDATA] = (apduSize - 5);
		result = sendApduDongle(dongle, in, apduSize, out, sizeof(out), &sw);
		if (result < 0) {
			fprintf(stderr, "I/O error\n");
			return 0;
		}
		if (sw != SW_OK) {
			fprintf(stderr, "Dongle application error : %.4x\n", sw);
			return 0;
		}
	}
	printf("Transaction submitted, waiting to be finalized\n");
	status = 1;

cleanup:
	if (dongle != NULL) {
		closeDongle(dongle);
	}
	exitDongle();

	if (transactions != NULL) {
		for (i = 0; i < transactionsNumber; i++) {
			if (transactions[i] != NULL) {
				freeTransaction(transactions[i]);
			}
		}
	}
	if (prevouts != NULL) {
		free(prevouts);
	}

	return status;
}
ISerializer& BinaryOutputStreamSerializer::operator()(std::string& value, const std::string& name) {
  writeVarint(stream, value.size());
  checkedWrite(value.data(), value.size());
  return *this;
}
ISerializer& BinaryOutputStreamSerializer::operator()(uint64_t& value, const std::string& name) {
  writeVarint(stream, value);
  return *this;
}
ISerializer& BinaryOutputStreamSerializer::operator()(int64_t& value, const std::string& name) {
  writeVarint(stream, static_cast<uint64_t>(value));
  return *this;
}
ISerializer& BinaryOutputStreamSerializer::beginArray(std::size_t& size, const std::string& name) {
  writeVarint(stream, size);
  return *this;
}