Last active
          December 3, 2021 08:22 
        
      - 
      
- 
        Save chen7897499/0dec82424af6c786eafacf029fc1d515 to your computer and use it in GitHub Desktop. 
    communicate with btcd node
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | [Application Options] | |
| datadir=./btcd/data | |
| listen=127.0.0.1:9333 | |
| simnet=1 | |
| nobanning=1 | |
| debuglevel=debug | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | require 'securerandom' | |
| require 'digest' | |
| require 'socket' | |
| require 'pry' | |
| require 'stringio' | |
| class String | |
| def to_bytes(length, byte_order='big') | |
| result = [self.rjust(length*2, '0')].pack('H*') | |
| result.reverse! if byte_order == 'little' | |
| return result | |
| end | |
| end | |
| def encode_varint(i) | |
| if i < 0xfd | |
| i.to_s(16).to_bytes(1, 'little') | |
| elsif i < 0x10000 | |
| '\xfd'.b + i.to_s.to_bytes(2, 'little') | |
| elsif i < 0x100000000 | |
| '\xfe'.b + i.to_s.to_bytes(4, 'little') | |
| elsif i < 0x10000000000000000 | |
| '\xff'.b + i.to_s.to_bytes(8, 'little') | |
| else | |
| raise "integer too large #{i}" | |
| end | |
| end | |
| def version | |
| result = 70015.to_s(16).to_bytes(4, 'little') | |
| result += 1.to_s(16).to_bytes(8,'little') | |
| result += Time.now.to_i.to_s(16).to_bytes(8, 'little') | |
| result += 1.to_s(16).to_bytes(8, 'little') | |
| result += "\x00".b * 10 + "\xff\xff".b + [127,0,0,1].map {|n| [n.to_s(16)].pack("h*") }.join | |
| result += 9333.to_s(16).to_bytes(2, 'big') | |
| result += 1.to_s(16).to_bytes(8, 'little') | |
| result += "\x00".b * 10 + "\xff\xff".b + [127,0,0,1].map {|n| [n.to_s(16)].pack("h*") }.join | |
| result += 9334.to_s(16).to_bytes(2, 'big') | |
| result += SecureRandom.random_bytes(8) | |
| result += encode_varint("/Satoshi:5.64/tinybit:0.0.1/".length) | |
| result += "/Satoshi:5.64/tinybit:0.0.1/" | |
| result += "\xff\xff\xff\xff".b | |
| result += "\x01".b | |
| end | |
| # Checksums use hash256 (where data is hashed twice through sha256) | |
| def hash256(binary) | |
| hash1 = Digest::SHA256.hexdigest(binary) | |
| hash2 = Digest::SHA256.hexdigest([hash1].pack("H*")) | |
| return hash2 | |
| end | |
| # Checksums are used when creating addresses | |
| def checksum(hex) | |
| hash = hash256(hex) # Hash the data through SHA256 twice | |
| return [hash].pack("H*")[0..3] | |
| end | |
| def message | |
| @payload = version | |
| result = "\x16\x1c\x14\x12".b | |
| result += "version" + "\x00".b * (12 - "version".length) | |
| result += @payload.length.to_s(16).to_bytes(4, 'little') | |
| result += checksum(@payload) | |
| result += @payload | |
| end | |
| def verack_message | |
| result = "\x16\x1c\x14\x12".b | |
| result += "verack" + "\x00".b * (12 - "verack".length) | |
| result += 0.to_s(16).to_bytes(4, 'little') | |
| result += checksum("") | |
| result += "" | |
| end | |
| def pong_message(nonce) | |
| @payload = [nonce].pack('Q') | |
| result = "\x16\x1c\x14\x12".b | |
| result += "pong" + "\x00".b * (12 - "pong".length) | |
| result += @payload.length.to_s(16).to_bytes(4, 'little') | |
| result += checksum(@payload) | |
| result += @payload | |
| end | |
| def extract_nonce(message) | |
| buf = StringIO.new(message) | |
| magic = buf.read(4) | |
| command = buf.read(12).delete("\x00") | |
| length = buf.read(4).unpack1('V') | |
| checksum = buf.read(4) | |
| payload = buf.read(length) | |
| raise ArgumentError, 'Checksum do not match.' unless checksum == checksum(payload) | |
| payload.unpack1('Q') | |
| end | |
| def gets(s) | |
| magic = s.read(4) | |
| command = s.read(12) | |
| length = s.read(4) | |
| checksum = s.read(4) | |
| payload = s.read(length.unpack1('V')) | |
| magic + command + length + checksum + payload | |
| end | |
| s = TCPSocket.new('localhost', 9333) | |
| s.write(message) | |
| # version message | |
| res = gets(s) | |
| puts 'received' | |
| p res | |
| # verack message | |
| res = gets(s) | |
| puts 'received' | |
| p res | |
| s.write(verack_message) | |
| msg_header_length = 4 + 12 + 4 + 4 # magiclength + commandlength + checksumlength + payload length value | |
| # ping pong handle | |
| loop do | |
| s.flush | |
| # res = s.recv(32, Socket::MSG_WAITALL) | |
| res = s.read(32) # ping message length | |
| puts 'received' | |
| p res | |
| nonce = extract_nonce(res) | |
| message = pong_message(nonce) | |
| s.write(message) | |
| end | |
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment
  
            
https://jeiwan.net/posts/programming-bitcoin-network-4/