>  기사  >  웹 프론트엔드  >  블록체인 구현을 위한 200줄의 코드 블록체인 예시에 대한 자세한 설명

블록체인 구현을 위한 200줄의 코드 블록체인 예시에 대한 자세한 설명

亚连
亚连원래의
2018-05-30 14:15:232840검색

이 글은 블록체인을 구현하기 위한 200줄의 코드를 주로 소개하고 있습니다. 매우 훌륭하고 참고할만한 가치가 있습니다. 필요한 친구들이 참고할 수 있습니다.

블록체인(블록체인, 트랜잭션 체인 블록)의 개념을 이해하는 것은 매우 간단합니다. 분산형(즉, 동일한 시스템이 아닌 다른 네트워크 장치에 배치됨) 데이터베이스는 증가하는 레코드 목록 호스팅을 지원합니다. 그러나 블록체인을 우리가 해결하도록 돕고자 하는 목표와 혼동하기 쉽습니다. 그 순간 사람들의 마음 속에 블록체인이라는 단어는 거래, 계약 또는 스마트 암호화폐의 개념과 매우 밀접하게 연관되어 있습니다.

여기서만 블록체인은 비트코인과 동일하지 않으며, 특히 소스 코드를 기반으로 하는 경우 블록체인의 기본 사항을 이해하는 것이 생각보다 쉽습니다. 이 기사에서는 JavaScript로 200줄의 코드로 구축된 간단한 모델을 제안합니다. 우리가 NaiveChain이라고 부르는 이 프로젝트의 소스 코드는 GitHub에서 찾을 수 있습니다. 1부 및 2부: 기능을 자세히 살펴보고 싶다면 치트 시트를 사용하고 표준 ECMAScript 6을 사용하겠습니다.
블록 구조

1단계 - 블록을 포함해야 하는 요소를 식별합니다. 단순화를 위해 구조적 무결성을 유지하기 위해 기록할 이전 블록의 인덱스(지수), 타임 스탬프(타임스탬프), 데이터(데이터), 해시 및 해시 등 가장 필요한 것만 포함합니다. 회로.

class Block { 
  constructor(index, previousHash, timestamp, data, hash) { 
    this.index = index; 
    this.previousHash = previousHash.toString(); 
    this.timestamp = timestamp; 
    this.data = data; 
    this.hash = hash.toString(); 
  } 
}

해시 단위

해시 블록은 데이터의 무결성을 유지하는 데 필요합니다. 우리의 경우 이는 SHA-256 알고리즘에 적용됩니다. 이러한 유형의 해싱은 마이닝과 관련이 없습니다. 이 경우 성능 증명을 통한 보호를 구현하지 않기 때문입니다.

var calculateHash = (index, previousHash, timestamp, data) => { 
  return CryptoJS.SHA256(index + previousHash + timestamp + data).toString(); 
};

세대 단위

블록을 생성하려면 이전 블록의 해시를 알아야 구조의 나머지 요소가 이미 결정되어 있습니다. 데이터는 최종 사용자가 제공합니다.

var generateNextBlock = (blockData) => { 
  var previousBlock = getLatestBlock(); 
  var nextIndex = previousBlock.index + 1; 
  var nextTimestamp = new Date().getTime() / 1000; 
  var nextHash = calculateHash(nextIndex, previousBlock.hash, nextTimestamp, blockData); 
  return new Block(nextIndex, previousBlock.hash, nextTimestamp, blockData, nextHash); 
};

저장 장치

블록체인 저장소 어레이를 사용하세요. 첫 번째 블록은 항상 "Genesis Block"으로 하드코딩됩니다.

var getGenesisBlock = () => { 
  return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7"); 
}; 
var blockchain = [getGenesisBlock()];

블록 무결성 확인

우리는 항상 장치나 회로의 무결성을 확인할 수 있어야 합니다. 특히 다른 유닛으로부터 새로운 유닛을 얻을 때, 이를 받아들일지 말지 결정해야 합니다.

var isValidNewBlock = (newBlock, previousBlock) => { 
  if (previousBlock.index + 1 !== newBlock.index) { 
    console.log('invalid index'); 
    return false; 
  } else if (previousBlock.hash !== newBlock.previousHash) { 
    console.log('invalid previoushash'); 
    return false; 
  } else if (calculateHashForBlock(newBlock) !== newBlock.hash) { 
    console.log(typeof (newBlock.hash) + ' ' + typeof calculateHashForBlock(newBlock)); 
    console.log('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash); 
    return false; 
  } 
  return true; 
};

가장 긴 체인을 선택하세요

회로의 블록 순서는 명시적으로 지정되어야 하지만 충돌이 발생하는 경우(예: 동일한 생성된 노드에서 동시에 두 개의 노드) 블록과 동일한 번호), 더 많은 수의 블록을 포함하는 회로를 선택합니다.

var replaceChain = (newBlocks) => { 
  if (isValidChain(newBlocks) && newBlocks.length > blockchain.length) { 
    console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); 
    blockchain = newBlocks; 
    broadcast(responseLatestMsg()); 
  } else { 
    console.log('Received blockchain invalid'); 
  } 
};

다른 네트워크 노드에 보내는 메시지

웹사이트의 필수 부분 - 다른 노드와의 데이터 교환. 네트워크 동기화를 유지하는 데는 다음 규칙이 사용됩니다.
노드가 새 유닛을 생성하면 이를 네트워크에 보고합니다.
로컬 머신이 새 잔치에 연결되면 마지막으로 생성된 블록에 대한 정보를 요청합니다. 더 큰 표시기가 있는 A 블록을 향하고 있으며 회로 또는 요청의 전체 정보 체인에 블록을 추가합니다.
동료 자동 검색은 수행되지 않으며 모든 링크는 수동으로 추가됩니다.

Control of Units

사용자는 HTTP 서버를 솔루션에 배치하여 어떤 방식으로든 노드를 제어할 수 있어야 합니다. 노드와 상호 작용할 때 다음 기능이 있습니다.

모든 유닛 목록 인쇄
사용자 생성 콘텐츠로 새 유닛 생성
목록 인쇄 또는 축제 추가.
상호작용하는 가장 직접적인 방법 - 컬을 통해:

노드의 모든 블록 목록 #

curl http://localhost:3001/blocks

Architecture

웹사이트가 주목할 가치가 있습니다. 두 개의 웹 서버를 의미합니다. 사용자 제어 설치를 위한 HTTP와 노드 간 P2P 연결 설치를 위한 WebSocket HTTP입니다.

다음은 200줄의 js 코드입니다

'use strict'; 
var CryptoJS = require("crypto-js"); 
var express = require("express"); 
var bodyParser = require('body-parser'); 
var WebSocket = require("ws"); 
var http_port = process.env.HTTP_PORT || 3001; 
var p2p_port = process.env.P2P_PORT || 6001; 
var initialPeers = process.env.PEERS ? process.env.PEERS.split(',') : []; 
class Block { 
  constructor(index, previousHash, timestamp, data, hash) { 
    this.index = index; 
    this.previousHash = previousHash.toString(); 
    this.timestamp = timestamp; 
    this.data = data; 
    this.hash = hash.toString(); 
  } 
} 
var sockets = []; 
var MessageType = { 
  QUERY_LATEST: 0, 
  QUERY_ALL: 1, 
  RESPONSE_BLOCKCHAIN: 2 
}; 
var getGenesisBlock = () => { 
  return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7"); 
}; 
var blockchain = [getGenesisBlock()]; 
var initHttpServer = () => { 
  var app = express(); 
  app.use(bodyParser.json()); 
  app.get('/blocks', (req, res) => res.send(JSON.stringify(blockchain))); 
  app.post('/mineBlock', (req, res) => { 
    var newBlock = generateNextBlock(req.body.data); 
    addBlock(newBlock); 
    broadcast(responseLatestMsg()); 
    console.log('block added: ' + JSON.stringify(newBlock)); 
    res.send(); 
  }); 
  app.get('/peers', (req, res) => { 
    res.send(sockets.map(s => s._socket.remoteAddress + ':' + s._socket.remotePort)); 
  }); 
  app.post('/addPeer', (req, res) => { 
    connectToPeers([req.body.peer]); 
    res.send(); 
  }); 
  app.listen(http_port, () => console.log('Listening http on port: ' + http_port)); 
}; 
var initP2PServer = () => { 
  var server = new WebSocket.Server({port: p2p_port}); 
  server.on('connection', ws => initConnection(ws)); 
  console.log('listening websocket p2p port on: ' + p2p_port); 
}; 
var initConnection = (ws) => { 
  sockets.push(ws); 
  initMessageHandler(ws); 
  initErrorHandler(ws); 
  write(ws, queryChainLengthMsg()); 
}; 
var initMessageHandler = (ws) => { 
  ws.on('message', (data) => { 
    var message = JSON.parse(data); 
    console.log('Received message' + JSON.stringify(message)); 
    switch (message.type) { 
      case MessageType.QUERY_LATEST: 
        write(ws, responseLatestMsg()); 
        break; 
      case MessageType.QUERY_ALL: 
        write(ws, responseChainMsg()); 
        break; 
      case MessageType.RESPONSE_BLOCKCHAIN: 
        handleBlockchainResponse(message); 
        break; 
    } 
  }); 
}; 
var initErrorHandler = (ws) => { 
  var closeConnection = (ws) => { 
    console.log('connection failed to peer: ' + ws.url); 
    sockets.splice(sockets.indexOf(ws), 1); 
  }; 
  ws.on('close', () => closeConnection(ws)); 
  ws.on('error', () => closeConnection(ws)); 
}; 
var generateNextBlock = (blockData) => { 
  var previousBlock = getLatestBlock(); 
  var nextIndex = previousBlock.index + 1; 
  var nextTimestamp = new Date().getTime() / 1000; 
  var nextHash = calculateHash(nextIndex, previousBlock.hash, nextTimestamp, blockData); 
  return new Block(nextIndex, previousBlock.hash, nextTimestamp, blockData, nextHash); 
}; 
var calculateHashForBlock = (block) => { 
  return calculateHash(block.index, block.previousHash, block.timestamp, block.data); 
}; 
var calculateHash = (index, previousHash, timestamp, data) => { 
  return CryptoJS.SHA256(index + previousHash + timestamp + data).toString(); 
}; 
var addBlock = (newBlock) => { 
  if (isValidNewBlock(newBlock, getLatestBlock())) { 
    blockchain.push(newBlock); 
  } 
}; 
var isValidNewBlock = (newBlock, previousBlock) => { 
  if (previousBlock.index + 1 !== newBlock.index) { 
    console.log('invalid index'); 
    return false; 
  } else if (previousBlock.hash !== newBlock.previousHash) { 
    console.log('invalid previoushash'); 
    return false; 
  } else if (calculateHashForBlock(newBlock) !== newBlock.hash) { 
    console.log(typeof (newBlock.hash) + ' ' + typeof calculateHashForBlock(newBlock)); 
    console.log('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash); 
    return false; 
  } 
  return true; 
}; 
var connectToPeers = (newPeers) => { 
  newPeers.forEach((peer) => { 
    var ws = new WebSocket(peer); 
    ws.on('open', () => initConnection(ws)); 
    ws.on('error', () => { 
      console.log('connection failed') 
    }); 
  }); 
}; 
var handleBlockchainResponse = (message) => { 
  var receivedBlocks = JSON.parse(message.data).sort((b1, b2) => (b1.index - b2.index)); 
  var latestBlockReceived = receivedBlocks[receivedBlocks.length - 1]; 
  var latestBlockHeld = getLatestBlock(); 
  if (latestBlockReceived.index > latestBlockHeld.index) { 
    console.log('blockchain possibly behind. We got: ' + latestBlockHeld.index + ' Peer got: ' + latestBlockReceived.index); 
    if (latestBlockHeld.hash === latestBlockReceived.previousHash) { 
      console.log("We can append the received block to our chain"); 
      blockchain.push(latestBlockReceived); 
      broadcast(responseLatestMsg()); 
    } else if (receivedBlocks.length === 1) { 
      console.log("We have to query the chain from our peer"); 
      broadcast(queryAllMsg()); 
    } else { 
      console.log("Received blockchain is longer than current blockchain"); 
      replaceChain(receivedBlocks); 
    } 
  } else { 
    console.log('received blockchain is not longer than received blockchain. Do nothing'); 
  } 
}; 
var replaceChain = (newBlocks) => { 
  if (isValidChain(newBlocks) && newBlocks.length > blockchain.length) { 
    console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); 
    blockchain = newBlocks; 
    broadcast(responseLatestMsg()); 
  } else { 
    console.log('Received blockchain invalid'); 
  } 
}; 
var isValidChain = (blockchainToValidate) => { 
  if (JSON.stringify(blockchainToValidate[0]) !== JSON.stringify(getGenesisBlock())) { 
    return false; 
  } 
  var tempBlocks = [blockchainToValidate[0]]; 
  for (var i = 1; i < blockchainToValidate.length; i++) { 
    if (isValidNewBlock(blockchainToValidate[i], tempBlocks[i - 1])) { 
      tempBlocks.push(blockchainToValidate[i]); 
    } else { 
      return false; 
    } 
  } 
  return true; 
}; 
var getLatestBlock = () => blockchain[blockchain.length - 1]; 
var queryChainLengthMsg = () => ({'type': MessageType.QUERY_LATEST}); 
var queryAllMsg = () => ({'type': MessageType.QUERY_ALL}); 
var responseChainMsg = () =>({ 
  'type': MessageType.RESPONSE_BLOCKCHAIN, 'data': JSON.stringify(blockchain) 
}); 
var responseLatestMsg = () => ({ 
  'type': MessageType.RESPONSE_BLOCKCHAIN, 
  'data': JSON.stringify([getLatestBlock()]) 
}); 
var write = (ws, message) => ws.send(JSON.stringify(message)); 
var broadcast = (message) => sockets.forEach(socket => write(socket, message)); 
connectToPeers(initialPeers); 
initHttpServer(); 
initP2PServer();

위 내용은 제가 모두를 위해 정리한 내용입니다. 앞으로 모든 분들께 도움이 되기를 바랍니다.

관련 글:

NodeJS 상위 프로세스와 하위 프로세스 간 리소스 공유 원칙 및 구현 방법

Vue의 휴대폰 번호, 이메일 정기 인증 및 60년대 인증 코드 전송 예시

Vue가 구현한 것 활성 클릭 전환 방법

위 내용은 블록체인 구현을 위한 200줄의 코드 블록체인 예시에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.