반응형
UTXO 조회하기
서명에 필요한 utxo를 테스트넷에서 가져옵니다. 가져온 utxo에서 전송에 필요한 금액 만큼만 사용하면 됩니다.
import axios from 'axios';
const Client = axios.create({
baseURL: 'https://test-insight.bitpay.com/api',
headers: { "Content-Type": "application/json" },
timeout: 10000
});
const fromAddress = "1J5RoyfyjLBcdGc2PCnN8wkfEUJms13vv8";
const utxos = await Client.post(`/addrs/utxo`, { addrs: fromAddress }).then(r => r.data);
실제 비트코인 주소입니다. 메인넷에서 테스트로 송금해주셔도 됩니다.
트랜잭션 생성하기
트랜잭션 생성에는 비트코인(bitcore-lib) 라이브러리를 사용하였습니다. 그리고 일단은 P2PKH 주소 서명만 예제 코드로 사용하였습니다. 주소의 prefix로 스크립트 유형을 알아낼 수 있습니다. 비트코인 주소 유형은 이곳 위키 를 참고하세요.
const bitcore = require('bitcore-lib');
const tx = new bitcore.Transaction();
if ( ["1", "m", "n"].includes(fromAddress.slice(0, 1)) ) { // P2PKH
tx.from(utxos);
} else {
// P2PK, P2SH, P2WPKH, Etc ...
}
tx.to(to, amount.toNumber());
tx.feePerKb(20000); // TX KB별 필요한 수수료 입력
tx.change(fromAddress); // 잔금 받을 주소 입력(HD지갑이라면 change 주소 사용)
const transaction = tx.uncheckedSerialize();
주소 prefix가 1이면(테스트넷은 m or n) P2PKH 입니다.
서명할 시그해시 계산하기
const hash = tx.inputs.map((input, index) => {
let sighash = bitcore.Transaction.Sighash.sighash(tx, 0x01, index, input.output.script);
sighash = bitcore.encoding.BufferReader(sighash).readReverse();
return sighash.toString("hex");
});
bitcore 라이브러리는 서명에 little-endian을 사용하고 있습니다. 그래서 계산된 hash를 다시 reverse 합니다.
트랜잭션에 서명값 추가하기
외부 서버나 디바이스에서 받아온 서명을 다시 트랜잭션에 추가합니다.
// sign 서버에 서명 요청하기
const signatures = await SignService.requestSignature(hash);
signatures.forEach((signature, index) => {
// signature 객체 생성
let sig = bitcore.crypto.Signature.fromCompact(
buffer.Buffer(signature, "hex")
);
// 시그해시 계산
const input = tx.inputs[index];
let hashbuf = bitcore.Transaction.Sighash.sighash(tx, 0x01, index, input.output.script);
hashbuf = bitcore.encoding.BufferReader(hashbuf).readReverse();
// 서명 검증
const ecdsa = bitcore.crypto.ECDSA({ hashbuf, sig });
ecdsa.set({ pubkey: ecdsa.toPublicKey() });
if (!ecdsa.verify().verified) {
return Errors.BAD_SIGNATURES;
}
// tx에 서명 추가
const signatureObj = new bitcore.Transaction.Signature({
publicKey: ecdsa.pubkey,
prevTxId: input.prevTxId,
outputIndex: input.outputIndex,
inputIndex: index,
signature: sig,
sigtype: 0x01 // SIGHASH_ALL.
});
tx.applySignature(signatureObj);
});
// 서명된 tx를 serialize 하기
const serializeTx = tx.serialize();
이제 마지막으로 serialized된 tx를 비트코인 노드서버로 send 하면 됩니다.
반응형
'개발 > 블록체인(암호화폐)' 카테고리의 다른 글
[블록체인] 이더리움(Ethereum) 공부 #3 - 트랜잭션과 서명 (0) | 2019.07.02 |
---|---|
[블록체인] 이더리움(Ethereum) 공부 #2 - HD 지갑과 니모닉 코드 (0) | 2019.07.02 |
[블록체인] 이더리움(Ethereum) 공부 #1 - 키와 주소 (0) | 2019.07.02 |