bitcoind를 이용해서 트랜잭션을 생성하는 방법을 알아보자. 편리하지만 제한된 기능만 사용할 수 있는 방법부터 불편하지만 강력한 기능을 사용할 수 있는 방법까지 다양하게 알아보자.
주로 bitcoin-cli를 활용하며 마지막에 curl을 사용하는 방법도 가볍게 다룬다.
초기 설정은 이전 글에서 다룬 내용을 참고하자.
이번 글에서는 로컬에서 비트코인 노드 2개를 띄운 상태를 가정한다. 아래와 같이 각 노드에서 편하게 명령어를 실행해보기 위해 별칭을 등록하자.
bc1 지갑에서 bc2 지갑으로 비트코인을 보내보자. 가장 쉬운 방법은 sendtoaddress 명령어를 이용하는 것이다.
bc2 지갑 주소를 얻기 위해 getnewaddress 명령어를 실행하자.
listunspent 명령어를 통해 현재 bc1 지갑의 UTXO 현황을 확인해보자.
각각 0.19843440 BTC, 2 BTC가 담긴 UTXO가 있음을 확인할 수 있다. 이제 sendtoaddress 명령어를 이용해서 bc2 지갑으로 0.1 BTC를 보내보자.
sendtoaddress 명령어를 실행하면 트랜잭션 생성과 동시에 네트워크로 전파된다. 그리고 해당 트랜잭션 ID가 출력된다.
트랜잭션의 세부 내용을 확인해보기 위해 getrawtransaction, decoderawtransaction 명령어를 순차적으로 실행해보자.
입력으로 0.19843440 BTC가 담긴 UTXO가 사용되었고, bc2 지갑으로 보내고 남은 비트코인은 bcrt1q9wk0js2hghrr3jy2vfjhxvrgd3cvnppv7n6dh0
(내 지갑 주소)로 보냈다.
입력에서 모든 출력을 뺀 (0.19843440 - 0.09840620 - 0.1 = 0.0000282
) 비트코인은 수수료로 사용된다.
다시 bc1 지갑의 UTXO를 확인해보자.
bc2 지갑으로 보내고 남은 UTXO는 보이지 않는다. 그것은 해당 트랜잭션이 블록에 포함된 후에 확인할 수 있다.
아직 블록에 포함되지 않은 트랜잭션을 확인해보자.
bc1 노드와 bc2 노드 모두 방금 전 생성된 트랜잭션이 멤풀에 있다는 것을 알고 있다.
이제 블록을 채굴해보자.
블록 채굴 후 멤풀은 비워졌으며 bc1 지갑의 UTXO에 사용하고 남은 비트코인이 잘 들어온 것을 확인할 수 있다.
sendtoaddress 명령어는 받는 사람의 주소와 보내는 비트코인 수량만 입력하면 자동으로 트랜잭션이 생성되고 네트워크로 전파되었다. 하지만 입력으로 사용될 UTXO를 선택하는 등의 세부적인 기능을 제공하지 않는다.
createrawtransaction 명령어를 사용하면 트랜잭션의 세부적인 내용을 입력할 수 있다.
아래는 createrawtransaction 명령어를 사용해서 2 BTC가 남은 UTXO를 입력으로 사용한다.
이 외에도 sequence, locktime 등의 필드를 입력할 수도 있다.
한 가지 주의할 점은 createrawtransaction 명령어는 수수료 계산을 자동으로 해주지 않는다는 점이다. 출력에서 사용한 비트코인을 제외하고 남은 잔금은 모두 수수료로 사용된다. 따라서 잔금이 발생하는 경우 이를 위한 출력도 추가해주어야 한다. 이에 대한 자세한 내용은 뒤에서 다룬다.
createrawtransaction 명령어는 트랜잭션 생성만 하고 네트워크로 전파하지는 않는다. decoderawtransaction 명령어를 이용해서 트랜잭션이 제대로 생성됐는지 확인해보자.
입력과 출력이 의도한대로 잘 적용되었다. sequence 4294967293
은 16진수로 0xFFFFFFFF
이며 RBF(트랜잭션 수수료 인상 기능)가 불가능한 상태를 의미한다.
해당 트랜잭션을 네트워크로 전파하기 위해서는 서명을 해야한다. signrawtransactionwithwallet 명령어를 이용해서 서명을 하자.
sendrawtransaction 명령어를 이용해서 서명된 데이터를 네트워크로 전파하자.
bc2 노드에서 채굴한 후에 bc1 지갑의 UTXO를 확인해보자.
2 BTC UTXO가 사라진 것을 확인할 수 있다.
이전 예제에서는 출력이 하나만 존재했지만 실사용 예와는 거래가 멀다. 이전 예제는 자신의 지갑을 (자신의) 다른 지갑으로 이동시키는 경우 말고는 발생하기 힘든 예다.
보통은 보내고자 하는 금액이 UTXO 목록에 있는 숫자와 일치하지 않으므로 보내고 남은 잔돈을 다시 자신의 지갑으로 보낸다. 이렇게 잔돈을 위해 사용되는 주소를 change address라고 부른다.
createrawtransaction 명령어를 이용해서 change address를 포함하는 트랜잭션을 만들어보자.
getrawchangeaddress 명령어를 이용해서 본인의 change address를 생성하자.
createrawtransaction 명령어를 이용해서 change address를 포함하는 트랜잭션을 생성하자.
change address를 포함하므로 출력이 2개가 되었다.
생성된 트랜잭션을 서명하고 네트워크로 전파하자.
생성된 트랜잭션을 포함하는 블록을 채굴하고 bc1 지갑의 UTXO를 확인해보자.
change address에 잔금이 들어온 것을 확인할 수 있다.
createrawtransaction 명령어는 강력하지만 수수료 계산이나 UTXO를 선택하는 과정이 번거롭고 실수의 여지가 있다는 위험도 있다. fundrawtransaction 명령어는 이런 단점을 보완해준다.
아래 createrawtransaction 명령어에서는 입력값을 빈 배열로 입력하고 있다. 또한 잔금(change address)에 대한 처리도 하지 않고 있다.
이렇게 생성된 트랜잭션을 fundrawtransaction 명령어에 입력하면 입력하지 않았던 부분을 자동으로 채워준다.
fundrawtransaction 명령어가 생성한 트랜잭션을 확인해보자.
fundrawtransaction 명령어가 자동으로 UTXO에서 하나를 선택해서 입력에 넣었다는 것을 확인할 수 있다. 또한 출력이 두 개인 것을 통해 change address도 자동으로 입력된 것을 확인할 수 있다. 이는 곧 수수료 계산도 자동으로 되었다는 것을 의미한다.
수수료 = 0.07830000 - 0.02000000 - 0.05827180 = 0.0000282 BTC
fundrawtransaction 명령어가 생성한 트랜잭션을 서명하고 네트워크로 전파하자.
블록을 채굴하고 bc1 지갑의 UTXO를 확인해보자.
잔금이 잘 들어온 것을 확인할 수 있다.
지금까지는 bitcoin-cli를 이용해서 트랜잭션을 생성하고 네트워크로 전파하는 방법에 대해 알아봤다. curl을 이용하면 bitcoin-cli 도움 없이 원격으로 bitcoind와 직접 소통할 수 있다.
curl을 이용해서 bitcoind의 API를 호출하기 위해서는 계정 정보와 포트 번호가 필요하다. 이 정보는 bitcoin.conf 파일에서 확인할 수 있다.
아래는 bitcoin.conf 파일의 일부 내용이다.
아래와 같은 형태로 curl을 이용해서 bitcoind API를 직접 호출할 수 있다.
위 bitcoin.conf 파일의 내용으로 실제 동작하는 명령어는 다음과 같다.
아래는 createrawtransaction 명령어를 호출하고 있다.