Python POS 알고리즘 기반 블록 체인 구현

블록 체인 의 공통 인식 알고리즘
비트 코 인 퍼 블 릭 체인 구조 분석 에서 탈 중개 화 디자인 을 실현 하기 위해 비트 코 인 은 공 통 된 협 의 를 설계 하고 이 협 의 를 통 해 시스템 의 안정성 과 공격 성 을 확보한다 고 언급 한 적 이 있다.그리고 우 리 는 지금까지 가장 광범 위 하 게 사용 되 고 사람들 에 게 가장 받 아들 여진 공 통 된 알고리즘 이 우리 가 이전에 소개 한 POW(proof of work)작업량 증명 알고리즘 이라는 것 을 알 고 있다.현재 시가 상위 2 위인 비트 코 인과 이 더 리 움 도 이 알고리즘 을 사용 하고 있다.
POW 컨 센서 스 알고리즘 이 큰 성공 을 거 두 었 지만 그 에 대한 의문 도 멈 춘 적 이 없다.그 중 가장 중요 한 원인 은 전력 소모 이다.불완전한 통계 에 따 르 면 POW 의 채굴 체 제 를 바탕 으로 소모 하 는 전력 은 매우 크 고 심지어 절대 다수의 국가 보다 전력 소비량 이 더 많다.이것 은 우리 의 자원 에 큰 낭 비 를 초래 했다.그 밖 에 비트 대륙 등 회사 의 강세 에 따라 산 력 의 높 은 집중 을 초래 했다.
상기 여러 가지 원인 을 바탕 으로 더 많은 공감 대 알고리즘 은 POS,DPOS,BPFT 등 이 제시 되 었 다.오늘 은 POS(proof stake)알고리즘 을 알 아 보 겠 습 니 다.
Proof of stake,권익 증명 으로 번역.권익 증명 은 간단하게 이해 하면 더 많은 token 을 가 진 사람 이 더 큰 확률 로 기장 권 리 를 얻 고 보상 을 받 을 수 있다 는 것 을 알 수 있 습 니 다.이 확률 은 구체 적 으로 얼마나 됩 니까?다음은 코드 구현 에서 보 여 드 리 고 분석 도 뒤에 놓 겠 습 니 다.물론 POS 가 POW 보다 더 좋 을 까?더 중심 화 되 나 요?지금 보기에 반드시 그렇지 는 않 기 때문에 우 리 는 여기 서도 누가 좋 고 누가 나 쁜 지 비교 하지 않 는 다.우 리 는 중립 적 인 입장 에서 단순히 POS 라 는 알고리즘 을 토론 했다.
코드 실전
Block 생 성
POS 알고리즘 을 실현 하려 면 하나의 체인 을 생 성 하 는 것 을 피하 기 어렵 고 체인 은 하나의 Block 에 의 해 생 성 되 기 때문에 먼저 Block 을 어떻게 생 성 하 는 지 살 펴 보 겠 습 니 다.물론 앞의 내용 에서 Block 을 어떻게 생 성 하 는 지,그리고 거래,UTXO 등 이 소개 되 었 습 니 다.오늘 우리 의 핵심 은 POS 를 실현 하 는 것 이기 때문에 Block 의 생 성에 대해 우 리 는 가장 간단 한 실현 방식 으로 여러분 들 이 핵심 적 인 내용 에 초점 을 맞 출 수 있 도록 하 겠 습 니 다.
우 리 는 세 가지 방법 으로 합 법 적 인 블록 을 만 드 는 것 을 실현 한다.
  • calculate_hash 컴 퓨 팅 블록 의 hash 값
  • is_block_유효한 블록 이 합 법 적 인지 검증 합 니 다
  • generate_block 블록 생 성
    
    from hashlib import sha256
    from datetime import datetime
    def generate_block(oldblock, bpm, address):
     """
     :param oldblock:
     :param bpm:
     :param address:
     :return:
     """
     newblock = {
      "Index": oldblock["Index"] + 1,
      "BPM": bpm,
      "Timestamp": str(datetime.now()),
      "PrevHash": oldblock["Hash"],
      "Validator": address
     }
     newblock["Hash"] = calculate_hash(newblock)
     return newblock
    def calculate_hash(block):
     record = "".join([
      str(block["Index"]),
      str(block["BPM"]),
      block["Timestamp"],
      block["PrevHash"]
     ])
     return sha256(record.encode()).hexdigest()
    def is_block_valid(newblock, oldblock):
     """
     :param newblock:
     :param oldblock:
     :return:
     """
     if oldblock["Index"] + 1 != newblock["Index"]:
      return False
     if oldblock["Hash"] != newblock["PrevHash"]:
      return False
     if calculate_hash(newblock) != newblock["Hash"]:
      return False
     return True
    여기 서 더욱 유연 하기 위해 우 리 는 클래스 의 실현 방식 을 사용 하지 않 고 함수 로 Block 생 성 을 실현 하여 쉽게 이해 할 수 있 을 것 이 라 고 믿 습 니 다.
    TCP 서버 만 들 기
    우 리 는 권익 증명 알고리즘 으로 기장 자 를 선택해 야 하기 때문에 많은 Node(노드)에서 기장 자 를 선택해 야 한다.즉,서버 가 노드 를 연결 시 키 는 동시에 정 보 를 노드 에 동기 화해 야 한다.따라서 TCP 긴 링크 가 필요 합 니 다.
    
    from socketserver import BaseRequestHandler, ThreadingTCPServer
    def run():
     # start a tcp server
     serv = ThreadingTCPServer(('', 9090), HandleConn)
     serv.serve_forever()
    여기 서 우 리 는 python 내 라 이브 러 리 socketserver 로 TCPServer 를 만 들 었 습 니 다.주의해 야 할 것 은 여기 서 우리 가 사용 하 는 다 중 스 레 드 생 성 방식 입 니 다.이렇게 하면 여러 개의 클 라 이언 트 가 동시에 연결 되 고 막 히 지 않도록 보장 할 수 있 습 니 다.물론 이 server 도 문제 가 있 습 니 다.바로 몇 개의 클 라 이언 트 가 연결 되 어 있 으 면 몇 개의 스 레 드 를 만 들 고 더 좋 은 방법 은 스 레 드 풀 을 만 드 는 것 입 니 다.이곳 은 테스트 이기 때문에 더욱 간단 한 방식 을 채택 했다.
    보시 다시 피 저희 가 TCPServer 를 만 들 때 HandleConn 을 사 용 했 습 니 다.하지만 아직 정의 가 되 지 않 았 기 때문에 HandleConn 을 정의 하 겠 습 니 다.
    메시지 처리 장치
    다음은 Handler 함 수 를 실현 하 겠 습 니 다.Handler 함 수 는 Client Node 와 통신 할 때 우리 의 Node 가 아래 의 기능 을 실현 해 야 합 니 다.
  • Node 는 balance(token 수량),즉 지분 수량 을 입력 할 수 있다
  • Node 는 방송 을 받 을 수 있 고 서버 동기 화 블록 과 기장 자 정 보 를 편리 하 게 해 야 합 니 다
  • 후보 명단 에 자신 을 추가 하 다.
    BPM 생 성 블록 을 입력 하 십시오4.567917.한 블록 의 합 법성 검증
    임무 가 꽤 많은 것 같 습 니 다.다음은 코드 가 실현 되 는 것 을 보 겠 습 니 다.
    
    import threading
    from queue import Queue, Empty
    #     
    block_chain = []
    temp_blocks = []
    candidate_blocks = Queue() #     ,       
    announcements = Queue()
    validators = {}
    My_Lock = threading.Lock()
    class HandleConn(BaseRequestHandler):
     def handle(self):
      print("Got connection from", self.client_address)
      # validator address
      self.request.send(b"Enter token balance:")
      balance = self.request.recv(8192)
      try:
       balance = int(balance)
      except Exception as e:
       print(e)
      t = str(datetime.now())
      address = sha256(t.encode()).hexdigest()
      validators[address] = balance
      print(validators)
      while True:
       announce_winner_t = threading.Thread(target=annouce_winner, args=(announcements, self.request,),
                 daemon=True)
       announce_winner_t.start()
       self.request.send(b"
    Enter a new BPM:") bpm = self.request.recv(8192) try: bpm = int(bpm) except Exception as e: print(e) del validators[address] break # with My_Lock: last_block = block_chain[-1] new_block = generate_block(last_block, bpm, address) if is_block_valid(new_block, last_block): print("new block is valid!") candidate_blocks.put(new_block) self.request.send(b"
    Enter a new BPM:
    ") annouce_blockchain_t = threading.Thread(target=annouce_blockchain, args=(self.request,), daemon=True) annouce_blockchain_t.start()
    이 코드 는 대부분의 학생 들 에 게 어 려 울 수 있 습 니 다.여기 서 우 리 는 다 중 스 레 드 방식 을 사용 하 는 동시에 메시지 온라인 스 레 드 간 통신 을 할 수 있 도록 대기 열 을 사 용 했 습 니 다.여기 서 대기 열 을 사용 하 는 것 도 우리 의 시스템 을 더욱 잘 확대 하기 위해 서 이다.나중에 가능 하 다 면 이 절 의 프로그램 은 분포 식 시스템 으로 쉽게 확대 할 수 있다.다 중 스 레 드 에서 처리 하 는 임 무 를 독립 된 서비스 로 나 눈 다음 에 메시지 큐 로 통신 하 는 것 은 간단 한 분포 식 시스템 입 니 다.(설 레 죠?)
    여기 가 어렵 기 때문에 코드 는 그래도 말 해 보 세 요.
    
     # validator address
      self.request.send(b"Enter token balance:")
      balance = self.request.recv(8192)
      try:
       balance = int(balance)
      except Exception as e:
       print(e)
      t = str(datetime.now())
      address = sha256(t.encode()).hexdigest()
      validators[address] = balance
      print(validators)
    이 부분 은 우리 가 언급 한 Node 클 라 이언 트 가 자신 이 후보 에 게 추가 한 코드 입 니 다.클 라 이언 트 를 연결 할 때마다 후 보 를 추가 합 니 다.여기에 우 리 는 추 가 된 타임 스탬프 의 hash 로 후 보 를 기록한다.물론 다른 방식 으로 도 사용 할 수 있 습 니 다.예 를 들 어 우리 코드 에 있 는 clientaddress
    
    announce_winner_t = threading.Thread(target=annouce_winner, args=(announcements, self.request,),
                daemon=True)
      announce_winner_t.start()
    def annouce_winner(announcements, request):
     """
     :param announcements:
     :param request:
     :return:
     """
     while True:
      try:
       msg = announcements.get(block=False)
       request.send(msg.encode())
       request.send(b'
    ') except Empty: time.sleep(3) continue
    그 다음 에 우 리 는 기장 권 을 얻 은 노드 정 보 를 모든 노드 로 방송 하 는 스 레 드 를 만 들 었 다.
    
    self.request.send(b"
    Enter a new BPM:") bpm = self.request.recv(8192) try: bpm = int(bpm) except Exception as e: print(e) del validators[address] break # with My_Lock: last_block = block_chain[-1] new_block = generate_block(last_block, bpm, address) if is_block_valid(new_block, last_block): print("new block is valid!") candidate_blocks.put(new_block)
    노드 가 입력 한 BPM 값 에 따라 블록 을 만 들 고 블록 의 유효성 을 검증 합 니 다.유효한 블록 을 후보 블록 에 넣 고 기장 자가 블록 을 체인 에 추가 하 기 를 기다 리 고 있 습 니 다.
    
    annouce_blockchain_t = threading.Thread(target=annouce_blockchain, args=(self.request,), daemon=True)
      annouce_blockchain_t.start()
    def annouce_blockchain(request):
     """
     :param request:
     :return:
     """
     while True:
      time.sleep(30)
      with My_Lock:
       output = json.dumps(block_chain)
      try:
       request.send(output.encode())
       request.send(b'
    ') except OSError: pass
    마지막 스 레 드 를 시작 하여 모든 노드 에 블록 체인 을 동기 화 합 니 다.
    다 봤 습 니 다.노드 와 Server 가 상호작용 하 는 부분 은 그 다음 에 가장 중요 한 부분 입 니 다.
    POS 알고리즘 구현
    
    def pick_winner(announcements):
      """
           
      :param announcements:
      :return:
      """
      time.sleep(10)
      while True:
        with My_Lock:
          temp = temp_blocks
        lottery_pool = [] #
        if temp:
          for block in temp:
            if block["Validator"] not in lottery_pool:
              set_validators = validators
              k = set_validators.get(block["Validator"])
              if k:
                for i in range(k):
                  lottery_pool.append(block["Validator"])
          lottery_winner = choice(lottery_pool)
          print(lottery_winner)
          # add block of winner to blockchain and let all the other nodes known
          for block in temp:
            if block["Validator"] == lottery_winner:
              with My_Lock:
                block_chain.append(block)
              # write message in queue.
              msg = "
    {0}
    ".format(lottery_winner) announcements.put(msg) break with My_Lock: temp_blocks.clear()
    여기 우리 pickwinner 는 기장 권 리 를 선택 합 니 다.우 리 는 token 수량 에 따라 목록 을 만 들 었 습 니 다.한 사람 이 기장 권 리 를 얻 을 확률 은:p = mount['NodeA']/mount['All']문자 설명 은 token 수가 전체 에서 차지 하 는 비례 입 니 다.예 를 들 어 총 수 는 100 개 이 고 그 는 10 개 이다.그러면 기장 권 을 얻 을 확률 은 0.1 이다.여기 서 핵심 부분 은 많이 다 르 지 않다.그 다음 에 노드 를 추가 하고 테스트 를 시작 하 자.
    POS 의 기장 방식 을 시험 하 다
    테스트 하기 전에 시작 부분 에서 해 야 할 일이 있 습 니 다.앞에서 우리 의 run 방법 은 보완 해 야 합 니 다.코드 는 다음 과 같 습 니 다.
    
    def run():
      # create a genesis block
      t = str(datetime.now())
      genesis_block = {
        "Index": 0,
        "Timestamp": t,
        "BPM": 0,
        "PrevHash": "",
        "Validator": ""
      }
      genesis_block["Hash"] = calculate_hash(genesis_block)
      print(genesis_block)
      block_chain.append(genesis_block)
      thread_canditate = threading.Thread(target=candidate, args=(candidate_blocks,), daemon=True)
      thread_pick = threading.Thread(target=pick_winner, args=(announcements,), daemon=True)
      thread_canditate.start()
      thread_pick.start()
      # start a tcp server
      serv = ThreadingTCPServer(('', 9090), HandleConn)
      serv.serve_forever()
    def candidate(candidate_blocks):
      """
      :param candidate_blocks:
      :return:
      """
      while True:
        try:
          candi = candidate_blocks.get(block=False)
        except Empty:
          time.sleep(5)
          continue
        temp_blocks.append(candi)
    if __name__ == '__main__':
      run()
    TCPServer 에 노드 추가
    프로그램의 복잡성 을 충분히 줄 이기 위해 tcp client 는 이 루어 지지 않 습 니 다.뒤쪽 으로 확장 할 수 있 습 니 다.어쨌든 우리 시스템 은 쉽게 확장 할 수 있 습 니 다.그 다음 에 우 리 는 다 중 스 레 드 부분 을 나 누 었 습 니 다.tcp client 를 실현 하 는 것 은 완전한 분포 식 시스템 입 니 다.
    그래서 우 리 는 Liux 자체 명령 nc 를 사용 합 니 다.nc 를 어떻게 사용 하 는 지 모 르 는 학생 들 이 google 이나 man nc 를 사용 할 수 있 습 니 다.

    서비스 시작 python pos.py 실행
    터미널 3 개 열기
    각각 아래 명령 을 입력 하 다nc localhost 9090터미널 출력
    Enter token balance:
    클 라 이언 트 가 서버 ok 에 연결 되 어 있다 는 뜻 입 니 다.
    POS 의 기장 방식 을 시험 하 다
    다음은 순서대로 제시 에 따라 조작한다.balance 는 기분 에 따라 조작 할 수 있 습 니 다.여 기 는 테스트 이기 때문에 100 을 입력 합 니 다.
    이 어 BPM 입력 을 알려 드 리 겠 습 니 다.앞서 말씀 드 렸 듯 이 BPM 을 입력 하 는 것 은 Block 을 만 들 기 위해 서 입 니 다.그럼 입력 하 세 요.9.ok 을 마음대로 입력 하 세 요.그 다음 에 잠시 기 다 려 서 기장 을 기다 리 겠 습 니 다.
    출력

    순서대로 서로 다른 터미널 에서 알림 에 따라 숫자 를 입력 하고 메시지 가 동기 화 되 기 를 기다린다.
    블록 체인 생 성
    다음은 제 가 얻 은 블록 정보 세 개 입 니 다.

    총결산
    위의 코드 에서 우 리 는 POS 알고리즘 을 바탕 으로 장 부 를 기록 하 는 완전한 체인 을 실현 했다.물론 여기 에는 확장 되 고 개선 할 만 한 부분 이 많다.
  • python 에서 다 중 스 레 드 비용 이 비교적 많 고 협 정 방식 으로 바 꿀 수 있 습 니 다
  • TCP 가 구축 한 긴 링크 는 TCPServer 를 바탕 으로 중심 화 된 방식 으로 P2P 대등한 네트워크 로 바 꿀 수 있 습 니 다4.567917.체인 의 정보 가 완전 하지 않다.
    4.567917.시스템 은 성분 포 식 을 확대 하여 더욱 건장 하 게 할 수 있다.
    대략 상기 몇 가 지 를 열 거 했 고 다른 것 은 넓 힐 수 있 는 곳 이 많 습 니 다.관심 이 있 는 친 구 는 먼저 놀 수 있 고 후 자 는 우리 뒤의 튜 토리 얼 을 기다 릴 수 있 습 니 다.(광고 에 미 처 손 을 쓸 수가 없다.하하)
    물론 언어 가 중요 하지 않 기 때문에 여기 서 저도 go 언어의 버 전 소스 주 소 를 실 현 했 습 니 다.
    go 언어의 실현 감각 은 좀 더 잘 이해 하고 우아 하 게 보 여야 한다.이것 도 고 언어 가 분포 식 분야 에서 더욱 잘 팔 리 는 이유 중 하나 입 니 다!
    항목 주소
    https://github.com/csunny/py-bitcoin/
    레 퍼 런 스
    https://medium.com/@mycoralhealth/code-your-own-proof-of-stake-blockchain-in-go-610cd99aa658
    총결산
    위 에서 말씀 드 린 것 은 소 편 이 소개 한 Python 이 POS 알고리즘 을 기반 으로 한 블록 체인 을 실현 하 는 것 입 니 다.여러분 께 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 메 시 지 를 남 겨 주세요.소 편 이 바로 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

    좋은 웹페이지 즐겨찾기