728x90

수업때 배운걸 바탕으로 코드르 짠건데

수업때 쓴 코드예제가 이거다(추정) 

https://newpouy.github.io/jekyll/update/2018/03/19/naivecoin-korean-translate-version.html

 

Naivecoin Korean Translate Version #1

navie코인 번역 원문: lhartikk.github.io

newpouy.github.io

 

우리팀이 한 내용은 ,시각화에서 꽤나 시간을 잡아먹었지만, 

제네시스 블록 만들고 

노드 켜면 제네시스 블록 만들고 db생성 연결돼서 제네시스 블록이 들어감

채굴하면 그 내용도 들어감

 

각노드가 db가지고 있어서 내용들어가고 ws웹소켓으로 둘이 연결을 시키면 블록 추가할때 받아옴. 길이가 긴쪽걸로 받아와. 지갑 생성은 지갑주소address띄우고 시각화정도만!

 

(우리팀한 거 백단내용 중간만 정리한거. 에러천국리뷰도 조만간 올리겠다 안에 팀플한 전체코드링크있음)

https://stepby-yun.tistory.com/115?category=0 

 

블록체인 채굴, p2p서버통신, 블록업데이트 완료 (코드 적어놓고 정리)

각 노드, 참여자 컴퓨터에 3001이 관리자 6001이 노동자.. http서버는 모든 걸 보여주기 용으로 돌리는거 라고 대충이해했는데.. 이후에 db서버랑, 리액트서버랑 얘네가 어떻게 맞물리는지 사실 아직

stepby-yun.tistory.com


~~최소한의 블록체인 짜기~~~ 내용출처 상위링크

이제 트랜젝션 거래 내용을 짜야하는데 전체 구조를 제대로 이해못했는지 잘안된다. 문서보면서 정리하면서 해보자

나름의 코드풀이임..

(보니까 얘는 TypeScript를 썼더라고 그래도 npm start하면 알아서 자바스크립트로 뽑아 변환해주더라)

 

  • 블록과 블록체인
  • 기존 데이터에 새로운 블록 더하기
  • 노드(node) 간 통신과 싱크 맞추기
  • 간단한 HTTP를 통한 노드 제어

(첫번째 장에 써있는 이거 . 이건 다 한거임 그래도 다시 보기.. 함수명이 좀 다르지만)

 

블록구조 짜기

 

블록구조- 순서 , 데이터, 타임스템프, 해쉬값(블록데이터기반으로 계산됨, 블록의 고유한 식별자기능), 이전해쉬값

 

class Block {

constructor (인덱스, 해시~~~)

 this.인덱스= 인덱스;

~~

}

 

(우리는 Block에 헤더랑 바디 넣고, BlockHeader추가로 만들어서 거기에 버전이랑 인덱스 넣었음)

 

최초의 블록(제네시스블록) - 블록체인의 시작. 안의 값은 일일이 넣어주면 됨.

const genesisBlock

 

블록체인 싹 저장할 배열 (javascript in memory 방식으로 저장. 컴끄면 사라짐)

const blockchain= []    //1장에서는 genesisBlock를 넣은 걸봐서 제네시스 블록 넣어서 보려나봄

 

 

필요한 함수 만들기

 

해쉬값계산함수

const calculateHash

 

 

다음블록만드는 함수(이전 해쉬 블록 알아야함)

const generateNextBlock

 

 

블록의 유효성 검사할 함수

 

그 조건임 

  • 이전 블록보다 인덱스값이 1 클 것.
  • previousHash값이 이전블록의 hash값일 것.
  • hash값이 유효한 값일 것. 다음의 코드로 이를 검사할 수 있어요.

const isValidNewBlock = (새블록, 이전블록) => {

1. 만약 이전블록인덱스가 새 블록인덱스보다 길이 더 길면

틀림 뱉어

2. 이전블록해시와 새블록이전해시가 같지 않으면

틀림뱉어

3. 새블록의 해시 계산한것이 새블록해시와 같지 않으면

틀림 뱉어

 

다 통과하면 맞음 뱉어

}

 

 

 

참고로 나 저기 들어가는 ,"새블록, 이전블록" 이렇게 써놓은 거, 파라미터(매개변수parameter)가 이름 내마음대로 지어줘도 되는건지 몰랐음.. 그래서 req, res도 막 거꾸로 써도 되더라고. 이전에 보내준 값(전달인자 argument)을 여기서 어떤 이름으로 쓸지 변수 정하고 이 함수 안에서 쓰는 것이었다!!!! 이전에 보내준 값이름이랑 이름이 달라도 상관없는 것!..ㅋㅋㅋ그동안 이름같은게 많길래 헷갈렸는데 이렇게 유동적이었다뉘 

 

 

 

 

블록의 구조 검사하는 함수 

const isValidBlockStructure {

블록 인덱스 타입은 숫자

블록 해시 타입은 문자열string(왜 끈, 줄이냐면 한글자씩연달아 메모리에 저장되는게 끈같아서..)

블록 시간기록, 타임스탬프는 숫자

블록 데이터,정보는 문자열

}

 

전체 블록체인을 검사하는 함수

최초의 블록검사하고, 이어지는 모든 블록검사할거야~

(이함수는 replaceChain, 새블록들어왔을때 전체 체인 교체할 경우에 쓸거임)

 

const isValidChain =(유효한정보의블록체인)=>{

최초의 블록을 json형태로 내보내라.

만약에 최조블록이 첫번째 인덱스가 아니면 틀림뱉어.

for문으로 돌릴건데, 두번째인덱스부터 블록길이까지 돌릴거임

만약에 새로들어온 i번째 블록의 검증이 실패하고, 새로들어온i-1번째 블록검증실패하면

틀림뱉어

 

다 통과하면 맞음 뱉어

}

 

 

 

블록체인은 원본체인 길이를 다같이 갖고 있는 개념이라서

유효성 검증 거친 옳은 체인은 하나만 존재해야해!

c가 채굴해서 블록체인에 연결한 다음에 

동시에 a도 채굴하고 b도 채굴했을때 누구꺼로 하냐의 고민을

더 긴 체인을 옳은 체인으로 간주해. 

(이유는 체인이 길다는 건 다른 노드가 아직 받지 못한 블록을 갖고 있다볼수있어서)

https://newpouy.github.io/jekyll/update/2018/03/19/naivecoin-korean-translate-version.html

그래서 만드는

 

긴체인으로 전체 교체하는 함수

const replaceChain =(새블록)=>{

만약에 새블록이 전체 블록체인을 검사하는 함수를 잘 통과됐고 새블록길이가 전체블록길이보다 길면

콘솔로 "받은 블록체인이 유효하다. 현재블록체인을 받은 블록체인으로 교체한다" 띄움

 

아니면

콘솔로 "받은 블록체인 안유효해" 띄움

}

 

 

다른 노드와 통신

 

노드(참여자) 사이에 통신이 있어야 블록체인할 수 있겠지? 그래야 탈중앙화해서 우리끼리 알아서 거래하지.

데이터 싱크를 맞춰야하기 때문에 계속 통신하면서 우리가 가진 원본이 같은지 확인해야되는 게 물론 가장 큰이유지.

 

  • 노드가 새 블록을 만들면 그것을 네트워크로 방출(발송,broadcast)해야한다.
  • 노드 간에 연결될 때, 각자 지니고 있는 가장 마지막 블록이 무엇인지를 파악한다.
  • 자기보다 긴 체인과 연결되면 상대가 가진 블록 중 내가 가진 블록 이후의 모든 블록을 추가하여 싱크를 맞춘다. (긴걸로 대체된다는 그 얘기임)

노드간의 통신에는 웹소켓을 쓸거임 

 

먼저 노드를 제어하기 위한 http서버를 만들자

 

const initHttpServer =(내포트) =>{

express모듈써서 쓸 서버 app이라고 만들어놓음

그리고 서버통해서 json형태로 정보 띄우게 할거임

어떻게 쓸거냐면

/blocks버튼 쓸거야-요청들어오면 getBlockchain함수, 기존에 있는 갖고 있는 블록 다 보이게 응답할거야

/mineBlock 버튼, 근데 정보를 내가 보내주는,, 

새블록은 요청한 바디의 데이터를 다음블록생성함수에 넣은거야.

새블록으로 응답할게

/peers 버튼, 웹소켓으로 연결한 주소랑 포트번호 보여줄게

/addPeer버튼 req.body.peer보내서 노드 연결해줄게. 

}

 

서버실행해.listen (내포트주소,()=>{

내포트주소는 여기야

})

 

 

 

이제 이 서버로 

  • 블록의 리스트 가져오기
  • 새로운 블록을 만들기
  • 노드 목록을 가져오거나 새로운 노드를 추가하기 curl명령어로도 노드를 제어할 수 있어요.

할수 있음

curl http://localhost:3001/blocks

get이거 써서 

 

 

 

전체구조

 

노드, 참여자는 

두개의 웹서버와 통신할거야. 

1. 사용자가 노드를 제어하기 위한 http서버

2. 다른 노드들과 통신하기 위한 웹소켓서버

 

(팀플때는 노드별로 웹소켓서버를 만들어줬었는데 둘이연결할 웹소켓서버 하나만 있으면 상관없겠네)

 

728x90
728x90

 

 

 

ㅋㅋ그놈의 에러ㅋ

걍 db안켜서..ㅋㅋ...

나한테 깔려있는 sql처럼 자동인줄알았지

 

sudo service mysql restart

 

 

이건 자동실행시켜주는 거.

 

 

 

 

 

728x90
728x90

알아본다면 당신은 천재임 (못알아봐도 천재)

각 노드, 참여자 컴퓨터에

3001이 관리자 

6001이 노동자..

http서버는 모든 걸 보여주기 용으로 돌리는거

 

라고 대충이해했는데.. 이후에 db서버랑, 리액트서버랑 얘네가 어떻게 맞물리는지 사실 아직도 서버관계를 정확하게 모르겠다! 

 

일단 코드 여기요 (지금까지 한 것만 포크해놓음)

 

https://github.com/jsoyun/4th-project-YunminBlock

 

GitHub - jsoyun/4th-project-YunminBlock: 4th BlockChain Project

4th BlockChain Project. Contribute to jsoyun/4th-project-YunminBlock development by creating an account on GitHub.

github.com

 

 

각 컴퓨터 참여자로 노드 만들어서 

p2p서버 전달 확인해봄

 

참고로 실행할 때는 

node node1/r_httpServer.js

이렇게 했다

 

 

두 서버 각각 열고 

3001
3002

 

 

get 요청인 blocks로 들어가보면

둘다 제네시스 블록이 잘 들어가 있음요 

 

서버 연결!!

post addpeers로 

3002한테 요청하는거임 

 

3002가 6001 웹소켓으로  상대 웹소켓 주소 ws 6001로 연결

문 똑똑

 

 

 

 

peers로 연결된거 확인!

 

 

이제 둘이 연결됐으니

3002에서 채굴해보겠음 

3002 채굴돼서 들어왔지?

 

 

그렇다면 3001을 새로고침해보면 3002랑 연결되어있고 그블록의 길이가 더 길어서 추가됨

 

 

연결되어있으니까 3002에서 연속 2개 추가해도 업데이트 됨

 

 

 

 

 

 

 

3001에서 블록채굴해도 마찬가지로 3002에서 업뎃됨 

연속으로 4,5 값 넣어서 블록추가함


서버 통신 코드

 

 

 

httpServer.js

post로 보내면 

data로 이름지어서 "data" : 웹소켓 주소 가능한거임

 

이 웹소켓 주소 data가 connectToPeers함수로 들어감 얘가 웹소켓 연결해줌

P2PServer.js

 

소켓에 넣고 메세지 핸들러 함수쓰고

얘네가 보내주는거 관리하는거임 

 

 

메세지 핸들러는 이렇게 여기서 변수로 지정해줬음 

(그 검증할 때 변수 10으로 다 잡아서 블록10개 이전과 비교해서 생성시간 알아내는 거 있잖아

이거요 blockchain.js

걔랑 비슷한 원리인듯

신기한게 컴퓨터는 바보라서 걍 숫자 넣어서 계산하는 거기 때문에 시간인지 뭔지 안적어도 가능했음)

 

 

대신 쓸때는 위처럼 MessageType.QUERY_LATEST 이런식으로 해야 얘가 찾겠지?

 

 

연결됐을 때 채굴하면 broadcast로 연결되어있는애들 전부한테 뿌려주는 거

(근데 생각해보니까 마지막 최신블록 담아서 보내주는거 말고도 아예 많이 다르면 전체 교체해야되는 replace함수 써야되는데 broadcast(initMessageHandler(ws)) 이걸로 해줘야 되는거 아닌가....? 흠 정리하고 다시 수정해봐야겠다. )

 

 

 

중간에 맞이했던 에러들

브로드캐스트에 저 함수를넣지 않은 것 말고도 있음

 

갑자기 이거 뜸

(node:11496) Warning: Accessing non-existent property 'Blocks' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
(node:11496) Warning: Accessing non-existent property 'getLastBlock' of module exports inside circular dependency                                                                     cular dependency
(node:11496) Warning: Accessing non-existent property 'createHash' of module exports inside circular dependency                                                                       de circular dependency
(node:11496) Warning: Accessing non-existent property 'isValidTimestamp' of module exports  circular dependency
inside circular dependency

이게 찾아보니까 순환참조? a스크립트에서 만든 함수 내보내고 b에서 a의 함수 가져왔는데 또 가져와서? 생기는 뭐 중복돼서 그런거라고 했는데 

이전에 안뜨다가 갑자기 떠서 당황... 작동은 되는데 불안하죠잉

 

결국 전역변수에 있는 애들 다 지역변수로 넣어서 함... 

 

이런식으로.. 

 

 

 

 

 

 

아 그리고 블록체인 에 

 

이 부분 틀렸다는데 

흠 내가 이해한 거는 새블럭을 현재 시간이랑 어느정도 오차범위까지는 인정하는 코드라고 봤거든 책도 그 얘기고..

 

 

흠..어렵군!!

 

 

 

 

 

728x90
728x90

참고로 나는 이 두 에러가 스벅의 부실한 와이파이 때문이었음.. 

응아니고 mariadb 실행안해서였음요!!  기존에 쓰던 mysql는 초기설정으로 자동실행되게 설정해놓은 거라 마리아디비는 쓸라면 실행해줘야됐음!!!!!! ()

 

ConnectionError [SequelizeConnectionError]: connect ETIMEDOUT 

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)   

 

 


+자동실행되는 설정

출처:  https://codecoco.tistory.com/category

 


db연결하는 법 

mysql과 같음 이 코드 mysql연결하는거 보고 한거임(시퀄라이즈가 다른 sql데이터베이스들도 호환가능해서)

출처는 책임 | Node.js 교과서 | 조현영 p.315

 

 

 

package.json에 npm start하기 위해 넣기

start 노드몬 앱 넣기

시작할거를 main에 app.js로 

{
  "name": "4th-project-yunminblock",
  "version": "1.0.0",
  "description": "소윤이 보아라",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon app"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.2",
    "morgan": "^1.10.0",
    "mysql2": "^2.3.3",
    "nunjucks": "^3.2.3",
    "sequelize": "^6.13.0",
    "sequelize-cli": "^6.3.0",
  },
  "devDependencies": {
    "nodemon": "^2.0.15"
  }
}

 

시퀄라이즈에 필요한 모듈패키지설치

npm i express morgan nunjucks sequelize sequelize-cli mysql2

npm i -D nodemon

 

 

설치 완료 후

 

npx sequelize init

 

하면 

config, models, migrations, seeders폴더가 생성됨

models폴더 안에는 index.js가 있음

 

몇개는 지금 블록체인중이라서 넣은거라 안따라해도 됨

index.js 를 이렇게 수정고우

const Sequelize = require("sequelize");
const env = process.env.NODE_ENV || "development";
const config = require(__dirname + "/../config/config.json")[env];
const db = {};

//기존
const sequelize = new Sequelize(
  config.database,
  config.username,
  config.password,
  config
);

db.sequelize = sequelize;

module.exports = db;

 

이제 시퀄라이즈 통해 express앱과 mysql연결할거임

app.js 파일 만들고 안에 코드 넣기

const express = require("express");
const path = require("path");
const morgan = require("morgan");
const nunjucks = require("nunjucks");

const { sequelize } = require("./models");

const app = express();
app.set("port", process.env.PORT || 3307);
app.set("view engine", "html");
nunjucks.configure("views", {
  express: app,
  watch: true,
});

sequelize
  .sync({ force: false })
  .then(() => {
    console.log("데이터베이스 연결성공");
  })
  .catch((err) => {
    console.log(err);
  });

app.use(morgan("dev"));
app.use(express.static(path.join(__dirname, "public")));
app.use(express.json());

app.use(express.urlencoded({ extended: false }));

app.use((req, res, next) => {
  const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`);
  error.status = 404;
  next(error);
});

app.use((err, req, res, next) => {
  res.locals.message = err.message;
  res.locals.error = process.env.NODE_ENV !== "production" ? err : {};
  res.status(err.status || 500);
  res.render("error");
});

app.listen(app.get("port"), () => {
  console.log(app.get("port"), "번 포트에서 대기중");
});

마리아db포트가 3307로 되어 있어서 이렇게 했는데

사실 상관없는거같긴함 (서버는 계속 헷갈리는데 db서버가 3307포트인건 알겠고 여기서 넣는 포트는 아마 localhost:로 화면에 띄워주는 포트라고 이해함요..네.. )

여기서 3001로 바꿔도 잘됨 config에 port주소가 3307로 잘들어가 있기만 하면 문제없는듯 그거는 마리아db연결용 이건 보여주는포트용으로이해햇음

 

 

이제 중요한거.

config 내용임!!!

 

나는 마리아 디비쓰니까 그 유저네임이랑 그 비번 그 host로 적어줘야 한다

마리아 디비의 port랑

그래서 이렇게 했다

{
  "development": {
    "username": "mariatest",
    "password": "1234",
    "database": "mariadb",
    "host": "localhost",
    "dialect": "mysql",
    "port": "3307"
  },
  "test": {
    "username": "mariatest",
    "password": "1234",
    "database": "database_test",
    "host": "0.0.0.0",
    "dialect": "mysql"
  },
  "production": {
    "username": "mariatest",
    "password": "1234",
    "database": "database_production",
    "host": "0.0.0.0",
    "dialect": "mysql"
  }
}

아마 두세번째 애들은 상관없을듯 혹시나 해서 저렇게 넣어둔거임

 

 

 

이제 npm start하면 끝!!!

 


 

 

사실 위에도 말했지만 나는 연결안된다고 에러떴었음

ConnectionError [SequelizeConnectionError]: connect ETIMEDOUT
    at ConnectionManager.connect

 

암튼 이거 몰라서 mariadb들어가서 확인해보려는데 접근이 안됨

 

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

 

 

sudo service mysql restart

이것도 해보고 계속 안되다가 

+아냐 이게 실행이야 이거 하니까 된거임!!

+

 

 

sudo mysql -u root -p

로 하니까 들어가짐

 

들어가서 문제 있나 확인함

 

흠... config랑 비교해봄 

user mariatest 인지 host localhost로 되어있나..

 

npm start했을 때 db없다길래 

npx sequelize db:create

로 생성하고

실행

npm start

 

 

안에도 잘있군

 

얏호

 

 

 

https://velog.io/@pier101/Linux-wsl-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8%ED%9A%8C%EC%9B%90%EA%B0%80%EC%9E%85-%EB%A7%8C%EB%93%A4%EA%B8%B0nginx

 

[Linux] wsl 환경에서 로그인,회원가입 만들기(+nginx)

wsl 환경에서 node.js+react(+nginx)를 활용해 웹페이지를 만들어 보면서 ubuntu 환경에서 서버를 어떻게 구축하는지에 대한 감을 익히고 서버 구성에 대해 알아볼 것이다.📢본 작업은 wsl상에서 서버를

velog.io

 

 

 

 

 

728x90
728x90

https://medium.com/@dongha.sohn/bitcoin-8-%ED%95%A9%EC%9D%98-consensus-90e879d80b16

 

Bitcoin#8: 합의(Consensus)

이전의 글들을 통해 거래의 구조와 검증방식, 블록의 구조를 살펴보았다.

medium.com

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=gitacademy01&logNo=222027103524 

 

P2P 네트워크를 이용한 블록체인

안녕하세요 여러분 :) 오늘은 블록체인에 대해서 알아보려고 합니다. 얼마 전 만난 AI 연구를 하시는 분...

blog.naver.com

(이거는 비교조건/p2p개념 링크)

 

주의!

 

나름의 이해라서 백퍼 맞지 않을 수 있음ㅎㅎ

(이해를 돕기 위해 설명해준 학우분 감사합니다.)

 

수업에서 블록생성하고 연결하고 검증하고 서버열어서 블록보여주고 이런 걸 해봤는데

 

드는 생각이 왜 p2p를 하지? 였음

노드간의 통신을 작동해야된다는데

 

 

local3001 서버 열고 여기서 블록생성하고 검증하면 여기가 중앙서버고

노드, 참여자용 서버로 만든 6001, 6002,6003은 블록 생성해서 중앙서버가 검증자해주는 건가? 

잉 그러면 탈중앙화가 아닌데? 혼돈;;;

 

내가 이해를 잘못하고 있었음

 

 

 

"먼저 블록 채굴에 성공한 채굴자는 해당 블록을 주변에 전파하게 된다. 중요한 사실은, 이때 전파하는 블록은 채굴에 성공했다고 확신할 수 없는 블록이며 검증을 거쳐 블록체인에 연결되어야 한다. 거래는 노드들에게 전파되며 검증의 과정을 거치듯, 블록 또한 검증을 거치게 되며 검증의 조건은 다음과 같다....."

 

 

우리 p2p하려고 웹소켓 써서 주고받는 통신하잖아

그 전에는 기본 포트는 컴퓨터 내에서 물리적으로 연결되어있으니까 접속이 가능한거고

 

웹소켓으로 내 컴퓨터를 3개의 컴퓨터로 분리하다고 치고 6001, 6002, 6003에 하나씩 컴퓨터가 있고

실제로는 하나니까 물리적으로 3001에 연결될 수 있는거라 서버는 3001만 열어도 될거같기도하고..

 

암튼 결론은!

내가 연 3001은 그냥 이 모든게 보이는 용도로만 쓰이는 보여주기용 서버이고 

실제로 블록 생성, 검증은 

노드들이 하는거임

노드들의 서버 6001, 6002, 6003

그니까 얘네끼리 통신하는 p2p서버로 하는거지.

 

처음에 시작했을 때 

제네시스 블록을 모든 노드들이 갖고 시작하고 

그 뒤에 줄줄이 블록을 생성하는 거임

 

이제 검증과정을 거쳐서 서로블록을 비교하고

황금블록 발견한 애꺼가 당첨되면 원본 블록체인에 연결되고

나머지는 허탕치고 다시 다음블록 만드는 거임

 

 

 

 

그 checkedValid 코드부분은 

//블록구조 유효한지
//현재 블록의 인덱스가 이전 블록의 인덱스보다 1만큼 큰지
//이전블록의 해시값과 현재 블록의 이전해시가 같은지
//데이터 필드로부터 계산한 머클루트와 블록헤더의 머클루트가 동일한지
//이 조건 다 맞으면 올바른 구조체이다

 

이 조건들로 블록이 진짜인지 증명하는거고

진짜 블록이어도 아직 당첨은 안된거지 원본에 연결안된거

 

이제 비교해서 당첨될라면

p2p끼리 통신..

누구꺼를 연결할걸로 할지...

 

chainedBlock에 

replaceChain 함수 주석처리 해놨는데 이거가 

p2pServer.js에서 이렇게 함수호출되어있음

이걸로 누구꺼 연결할지 찾는거 아닐까 짐작..

 

블록들 비교까지 한다면

 어떻게 하는지는 모르겠다 어렵다!!!

 

 

아무튼 해야되는거는 

 

블록마이닝(채굴)/ 지갑생성/ 현재 상황 시각화 / DB 채굴 저장

 

사실상 지갑생성까지 수업때 한거긴한데

 

위같은 비교검증은 없어서

완전한 블록체인은 아닌거같고..흠 

 

 

 

 

 

 

 

 

 

 

 

728x90
728x90

어제 학원사람들이라 하면서 깨달은 점이랑 정리못했던 서버구축 내용 써보자~

서버 구축 코드는 이거 보면서 함요 https://blckchainetc.tistory.com/m/332

 

[119일차] 블록체인 네트워크 웹소켓 http ws 웹서버 구축

P2P (Peer to Peer) 구현 방법 -> WebSocket -> socket.io = 웹소켓으로 웹으로 구성할 때 필수적인 구성을 미리 만들어 놓은 패키지  이전 node.js chatting을 만들 때 사용함  기본 기능 외 여러가지 기능이..

blckchainetc.tistory.com

 

p2p 구현하기 위해서 서버 구축을 해보자!

(p2p peer to peer 노드, 참여자들간의 통신을 의미한다고 생각하면 됨!)

ws, 웹소켓쓸거임

 

블록체인은 대략적으로 크게 두개의 포트가 빌요한데

1. 중앙서버! 

서버- 클라이언트 

걍 작업, 블록생성한거 보여주는 데라고 이해함

(블록생성하고 작업하는 서버라고 생각했는데 검증과 생성을 서버 나눠서 따로 할 수도 있겠네.. 아니다 서버 안나누고 실행만 분리해도 될거같고..)

2. 노드끼리 통신

 

웹서버 구축의 기초 작업! 셋팅 시작!!

1. server - client http 서버 만들기

npm i express로 설치

 

//HTTP Server 초기화,P2P Server 초기화, 지갑 초기화
//(사용자와 노드간의 통신)

//client http 서버 만들기 express 사용
const express = require("express");
const app= express();
const port = process.env.PORT ||3000
const bodyParser = require('body-parser')
//블럭 가져오기
//현재 있는 블록들 가져와주는 함수
const {getBlocks} = require('./chainedBlock.js');

//바디파서 써서 json으로 볼예정임
app.use(bodyParser.json());
//blocks버튼임
app.get('/blocks',(req,res)=>{
    res.send(getBlocks())
})
app.listen(port,()=>{
    console.log(`server start port ${port}`)
    
})

서버 3000 잘 열렸고 

 

포트 변경도 해봄

(여기서 PORT변수로 명령어로 변수 값 변경한다고 생각하면 됨)

다시 3000으로 돌아와서

 

서버에 블록 가져와 보자!!

 

chainedBlock.js 에 만들었던 (이전 글에 코드 있음요)

blocks를 가져올거야. 

(chainedBlock.js에서 module.export로 getBlocks내보내기 해서 가져올 수 있음)

//현재가지고 있는 블록가져오는 함수
const {getBlocks} = require('./chainedBlock.js');

이걸로 함수 호출해서 기존 블록가져옴

app.get('/blocks',(req,res)=>{
    res.send(getBlocks())
})

 

 

이제 get잘되는지 확인해보자!

curl -X GET http://localhost:3000/blocks
curl http://localhost:3000/blocks -X GET   (요것도 가능!)

아 근데 curl 자체 의미하는게

"curl은 사용자 상호 작용 없이 작동하도록 설계된 서버에서 또는 서버로 데이터를 전송하기 위한 명령줄 유틸리티입니다"

그니까 명령어로 포스트맨,ARC같은거 안써도 볼 수 있는건데

나는 썼다

advanced REST client 확장자 설치해서 사용했음

 

 

여기서도 확인할 수 있겠죠

 

 

아!! 참고로 get post 알다가도 모르게 계속 헷갈렸는데 

다시금 이해함

 

post는 데이터 전송하고

get은  정보를 요청하는거! 그니까 버튼같은 역할이라고 생각하면 쉬움

이거 누르면 원하는 정보들이 보여지는거임

 

 

/blocks로  get으로 요청했으니까 

기존 제네시스 블록이 보이지

 

 

 

그럼 데이터 전송, 즉 추가하는 거 해보자

 

블록을 추가하는 것을 웹서버에서 해보자고

 

post로 해야겠지

 

//HTTP Server 초기화,P2P Server 초기화, 지갑 초기화
//(사용자와 노드간의 통신)

//client http 서버 만들기 express 사용
const express = require("express");
const app= express();
const port = process.env.PORT ||3000
const bodyParser = require('body-parser')
//블럭 가져오기
const {getBlocks,nextBlock} = require('./chainedBlock.js');
const {addBlock}= require('./checkValidBlock')

//바디파서 써서 json으로 볼예정임
app.use(bodyParser.json());
//blocks버튼임
app.get('/blocks',(req,res)=>{
    res.send(getBlocks())
})
app.listen(port,()=>{
    console.log(`server start port ${port}`)
    
})
//블록추가하기
app.post('/mineBlock',(req,res)=>{
    const data = req.body.data || []
    console.log(data)
    const block = nextBlock(data)
   addBlock(block)
   res.send(getBlocks())
})

바디데이터(아니면 빈배열)를 데이터로 이름 짓고 

다음블록생성하는 함수에 데이터 넣음

 

데이터 넣은 걸 block으로 이름 짓고 

그 블록을 블록배열에 추가한다!

(참고로 addBlock함수는 checkedValied에서 가져왔음)

그리고 getBlock함수로 지금 블록배열다 보이게 한다.

 

data로 변수 설정해서 "data"라고 하는 거임

 

 

이제 get요청인 blocks버튼 눌러보면요

배열에 추가된거 볼 수 있다.

 

 

 

 

좀 헷갈리는 거는 

chainedBlock에도 addBlock함수가 있고

checkedValid에도 addBlock함수가 있음

 

그래서

그냥 연결하는 체인드블록에서걸로

addBlock가져와서 쓰니까 오류났었음

블록구조가 유효한지 확인해야돼서 그런것도 있는데

둘 차이가 넣는 값이 다른거같은데 

bodyDate여서 그런가...흠 여긴 잘 모르겠군!

728x90
728x90

https://gdtbgl93.tistory.com/63

 

Git push가 안되는 경우 (fatal: refusing to merge unrelated histories)

로컬 저장소에 있는 프로젝트를 깃허브 사이트를 통해 만든 저장소로 push 하는 경우에 이런 메세지가 뜨는 경우가 있다. 1 2 3 4 5 6 7 8 C:\Users\gitProject>git push origin master To https://github.co..

gdtbgl93.tistory.com

 

 

push 안되길래 

pull먼저 해보려는데 다 안되길래

 

1
git pull origin 브런치명 --allow-unrelated-histories
cs

이거 하니까 되더라 

 


 

깃 데스크탑써서 큰 걱정은 없지만

 

 

 

 

 

이것도 한번 읽어봤다..

origin/branch 랑

branch 뭐가 다른지..

 

흠 대충 이해해서는 

branch는 내 로컬이고 

origin/branch가 깃헙에 넘어가는 거같음요..

 

"여기에서 branch_name은 로컬 분기인 반면, origin/branch_name은 원격 추적 분기입니다. 원점에 있는 해당 분기의 상태를 반영합니다..."

 

하지만 다 이해하진 못했다!

 

https://stackoverflow.com/questions/26125162/difference-between-origin-branch-name-and-branch-name

 

difference between origin/branch_name and branch_name?

for pushing to bitbucket. If I do: git push origin origin/branch_name my commits are not pushed. Total 0 (delta 0), reused 0 (delta 0) If I do git push origin branch_name my commits are pushed:

stackoverflow.com

 

728x90
728x90

먼저 꿀팁을 나눠준 학우들에게 감사합니다..

 

박수 짝짝짝

 

평소하던데로 

깃허브에서 

레포지토리 만들고 

주소 복사한다음에

 

깃데스크탑에 들어와서 

요기서 깃클론하고

 

작업할 때 

오픈 비주얼 코드 누르고 

터미널 켜져 있으면 

그걸로 하고 아니면 새 터미널들어가서 켜고

 

 

아래 보면

터미널이 원래 cmd로 되어있을건데

 

이걸 우분투로 바꿔주면

 

짠 

다가려놔서 안보이겠지만

wsl 작업창이 됐고요

/mnt 경로가 cd

커밋도 잘되고요

 

 

 

 

 

 

/mnt 경로는 바로

mnt

mnt는 mount의 약자 뜻을 가진 경로. 리눅스 프로그램에 기기의 탈부착으로 임시로 연결된 경로가 생기면 해당 경로에서 확인할 수가 있습니다. 현재 프로젝트의 AWS에는 연결된 외부 장치나 시스템이 없으므로 아무런 경로가 나오지 않습니다. 하지만 시스템의 용량을 확장할 때나 WSL에서 윈도우 시스템을 인식할 때 해당 경로로 인식할 수가 있습니다.

//WSL에서의 윈도우 인식
///mnt 경로
c d wsl

여기서 C는 Windows에서의 C 드라이브를 의미합니다.

출처: https://tecoble.techcourse.co.kr/post/2021-10-18-linux-file-directory-system/

 

 

 

 

728x90
728x90

겨우됐다 지갑생성하기....

 

chainedBlock에 

return을 빼먹어서 였음...

 

chainedBlock.js 코드전체

더보기
const fs = require('fs')
const merkle = require('merkle')
const cryptojs =require('crypto-js') 
// const { randomBytes } = require('crypto')
const random = require('random')
const { get } = require('http')

//예상 채굴 시간과 난이도 조절 단위수를 변수로 설정한다
const BLOCK_GENERATION_INTERVAL = 10  //second
const DIFFICULT_ADJUSTMENT_INTERVAL = 10 //in blocks




//블럭 형태 (헤더, 바디)
class Block{
        constructor(header, body){
		this.header = header
		this.body = body
	}
}

class BlockHeader{
        constructor(version,index, previousHash, timestamp, merkleRoot,difficulty, nonce){
	     this.version = version
	     this.index = index
	     this.previousHash = previousHash
	     this.timetamp = timestamp //블럭만들어진 시간
	     this.merkleRoot = merkleRoot
	    //  this.bit = bit
		this.difficulty = difficulty //채굴난이도. 아직안씀
	     this.nonce = nonce //넌스(문제풀기위해 대입한 횟수) 아직 안씀

	}
}

//버전계산하는 함수 
function getVersion(){
	const package = fs.readFileSync("package.json")
	// console.log(JSON.parse(package).version)
	return JSON.parse(package).version

}


//getVersion()

function createGenesisBlock(){
	const version = getVersion()
	const index= 0 //맨처음이라 인덱스0
	const previousHash = '0'.repeat(64) //sha256암호가 64자리니까 0을 64자리로 바꿔줌
	// const timestamp = parseInt(Date.now()/1000)
	//비트코인 날짜로..비트코인최초탄생일 2009/01/03 6:15pm (UTC)
	const timestamp = 1231006505  
	const body = ['제네시스블록 바디임요']
	const tree = merkle('sha256').sync(body) //바디값불러와서 sha256으로 암호화
	const merkleRoot = tree.root() || '0'.repeat(64)
	//루트값없으면 || 뒤에값 출력
	const difficulty = 0 //헤더값에 난이도 아직 0임
	const nonce = 0

	// console.log("version : %s, timestamp: %d, body : %s",version,timestamp,body)
	// console.log("previousHash : %d", previousHash);
	// console.log("merkleRoot : %d", merkleRoot);

	const header = new BlockHeader(version,index, previousHash, timestamp, merkleRoot, difficulty,nonce)
	return new Block(header, body)

}

//const block = createGenesisBlock()
//console.log(block)


//블록저장할수있는애들, 여러개 들어갈 수 있는 배열을 만들어줌
let Blocks = [createGenesisBlock()]


//현재 있는 블록을 다 리턴해주는 함수, 블럭목록 부르는 함수
function getBlocks(){
	return Blocks
}
//제일 마지막에 만든 블록 가져오기
function getLastBlock(){
	//길이 1이니까 1-1 =0 즉 첫번째배열 불러와 
	return Blocks[Blocks.length - 1]

}

//data에는 블록이 들어오는거임, 이블록을 가지고 해시값을 만들어내는 것임
// function createHash(data){
// 	const {version, index,previousHash,timestamp,merkleRoot,difficulty,nonce}= data.header
// 	const blockString = version + index + previousHash + timestamp + merkleRoot + difficulty + nonce
// 	const hash = cryptojs.SHA256(blockString).toString()
// 	return hash
// }
function createHash(data){
	//인자로 받은 것중에 헤더를 뽑아내서
	const {version, index, previousHash, timestamp, merkleRoot, difficulty, nonce} = data.header
	const blockString = version + index + previousHash + timestamp + merkleRoot + difficulty + nonce
	//다 합쳐서 해시로 만들고 리턴
	const hash = cryptojs.SHA256(blockString).toString()
	return hash
}

function calculateHash(version, index, 
		previousHash,timestamp,merkleRoot,difficulty,nonce){
//헤더의 값에 nonce값을 추가해서 모두 더한 string을 가지고 암호화 
//한 결과 hash를 내보낸다
	const blockString = version + index + previousHash + timestamp + merkleRoot + difficulty + nonce
	const hash = cryptojs.SHA256(blockString).toString()
	return hash
}
// const genesisBlock =createGenesisBlock()
//const testHash = createHash(block)
// console.log(genesisBlock)


//다음블록 만들었을 때 기존 블록 정보 가져와
function nextBlock(bodyData){
	//마지막 블럭, 이전블록으로
	const prevBlock = getLastBlock()
	const version = getVersion()
	const index = prevBlock.header.index + 1
	//이전 블록의 해시값
	const previousHash = createHash(prevBlock)
	const timestamp = parseInt(Date.now()/1000)
	const tree = merkle('sha256').sync(bodyData)
	const merkleRoot = tree.root() || '0'.repeat(64)
	//난이도 조절하는 함수 추가 
	const difficulty = getDifficulty(getBlocks())
    // const nonce = 0
    // const header = new BlockHeader(version, index, previousHash,timestamp,merkleRoot,bit,nonce)
	const header = findBlock(version, index, 
		previousHash,timestamp,merkleRoot,difficulty)
	return new Block(header,bodyData)


}
// const block1 = nextBlock(["tranjaction1"])
// console.log(block1)


function addBlock(bodyData){
	const newBlock = nextBlock(bodyData)
	Blocks.push(newBlock)
}
// addBlock(['transaction1'])
// addBlock(['transaction2'])
// addBlock(['transaction3'])
// addBlock(['transaction4'])
// addBlock(['transaction5'])
// console.log(Blocks)

//0103
// function replaceChain(newBlocks){
// 	if (isValidChain(newBlocks)){
// if 	((newBlocks.length> Blocks.length) ||
// (newBlocks.length=== Blocks.length) && random.boolean()){
// 	Blocks = newBlocks
// 	broadcast(responseLatestMsg())
// 	} 
// }
// 	else {
// 		console.log("받은 원장에 문제가 있음")
// 	}
// }
function hexToBinary(s) {
	//헤더부분을 sha256 암호화한 결과
	//16진수 64자리를 2진수로 변환하기
	const lookupTable = {
		'0' : '0000', '1' : '0001', '2': '0010', '3' : '0011',
		'4' : '0100', '5' : '0101', '6': '0110', '7' : '0111',
		'8' : '1000', '9' : '1001', 'A': '1010', 'B' : '1011',
		'C' : '1100', 'D' : '1101', 'E': '1110', 'F' : '1111'
	}

	let ret = "";
	for(let i = 0; i < s.length; i++){
		if (lookupTable[s[i]]) {
			ret += lookupTable[s[i]];
		}
		else { return null; }
	}
	return ret;
}
function hashMatchesDifficulty(hash, difficulty) {
	//difficulty를 이용해 만든 조건을 만족하는지 hash값과 대조해
	//조건에 해당되면 블록 생성
	const hashBinary = hexToBinary(hash.toUpperCase())
	 //difficulty 난이도가 높아짐에 따라 0개수가 늘어남 
	const requirePrefix = '0'.repeat(difficulty)
	//높으면 높을수록 조건을 맞추기가 까다로워짐(nonce값과 time값이 바뀌면서 암호화값이 달라진다.)
	return hashBinary.startsWith(requirePrefix)

}

function findBlock(currentVersion, nextIndex, previousHash, nextTimestamp,
	merkleRoot, difficulty) {
		//calculateHash값이 조건이 맞을때까지 while문으로 반복
		//조건문 반복할때마다 nonce값 증가
		let nonce = 0;
		while (true) {
			var hash = calculateHash(currentVersion, nextIndex, previousHash, nextTimestamp,
				merkleRoot, difficulty,nonce)
				if (hashMatchesDifficulty(hash,difficulty)){
					return new BlockHeader(currentVersion, nextIndex, previousHash, nextTimestamp,
						merkleRoot, difficulty,nonce)

				}
				nonce++ ;
				
		}
	}

	function getDifficulty(blocks){
		const lastBlock = blocks[blocks.length -1]
		if (lastBlock.header.index !==0 && lastBlock.header.index
			% DIFFICULT_ADJUSTMENT_INTERVAL === 0){
				//마지막 블럭헤더인덱스가 0이 아니고
				//난이도 조절수만큼 나누고 나머지가 0이면

				//난이도 조정함수 실행
				return getAdjustDifficulty(lastBlock,blocks)
			}
			//난이도 리턴
			return lastBlock.header.difficulty
	}

	function getAdjustDifficulty(lastBlock, blocks){
     // 지금 블록에서 난이도 조절 단위 수만큼의 전 블록과의 time 
	 //즉, 생성시간을 비교해서 자신의 예상 시간보다 느리거나 빠르면 난이도를 조절한다.
    //적당하면 난이도가 유지되고 블럭의 생성시간이 느리면 난이도를 낮추고, 빠르면 난이도를 높인다.
		const preAdjustmentBlock = blocks[blocks.length - DIFFICULT_ADJUSTMENT_INTERVAL];
		//시간
		const elapsedTime = lastBlock.header.timestamp - preAdjustmentBlock.header.timestamp
		const expectedTime = BLOCK_GENERATION_INTERVAL * DIFFICULT_ADJUSTMENT_INTERVAL;

		if (elapsedTime/2 > expectedTime) {
			return preAdjustmentBlock.header.difficulty +1;
		}
		else if (elapsedTime * 2 < expectedTime){
			return preAdjustmentBlock.header.difficulty -1 
		}
		else {
			return preAdjustmentBlock.header.difficulty
		}
	}

	function getCurrentTimestamp(){
		//Math.round 반올림함수
		return Math.round(Date().getTime()/ 1000);
	}

	function isValidTimestamp(newBlcok, prevBlock){
		if (newBlock.header.timestamp - prevBlock.header.timestamp > 60)
			return false
		if (getCurrentTimestamp()- newBlock.header.timestamp > 60)
		    return false
		return true
		

	}




module.exports = { hashMatchesDifficulty, isValidTimestamp, getBlocks, createHash,
	 Blocks, getLastBlock, nextBlock, addBlock, getVersion, 
	 createGenesisBlock };    //내보내주는거

httpServer.js

더보기
const express = require("express")
const bodyParser = require("body-parser")
const {getBlocks, nextBlock,getVersion} = require('./chainedBlock.js')
const {addBlock}= require('./checkValidBlock')
const { connectToPeers, getSockets } = require("./p2pServer.js")
const {getPublicKeyFromWallet, initWallet} = require("./encryption")

const http_port = process.env.HTTP_PORT || 3001

function initHttpServer(){
	const app = express()
	app.use(bodyParser.json())
	//추가
	app.post("/addPeers", (req,res)=>{
		const data = req.body.data || []
		console.log(data);
		connectToPeers(data);
		res.send(data);

	})
	app.get("/peers", (req, res)=> {
		let sockInfo = []

		getSockets().forEach(
			(s)=>{
				sockInfo.push(s._socket.remoteAddress+":"+s._socket.remotePort)
			}
		)
		res.send(sockInfo)
	})

	app.get("/blocks",(req,res)=>{
 
		res.send(getBlocks())

	})
	app.get("/version",(req, res)=>{
		res.send(getVersion())
	})

	app.post("/mineBlock",(req,res)=>{
		const data = req.body.data || []
		console.log(data)
		const block = nextBlock(data)
		addBlock(block)
		// res.send(block)
		res.send(getBlocks())
	})

	app.post("/stop", (req,res)=>{
		res.send({"msg":"Stop Server!"})
		process.exit()
	})
	app.get("/address", (req,res)=>{
		initWallet()
		const address = getPublicKeyFromWallet().toString();
		console.log(getPublicKeyFromWallet())
		if(address != "") {
			res.send({"address" : address})
		}
		else {
			res.send("empty address!")
		}
	})
	app.listen(http_port,()=>{
		console.log("Listening Http Port : "+ http_port)
	})


}

initHttpServer()

 

encryption.js

더보기
const fs = require("fs")
//타원곡선개념을 사용한 디지털 터널알고르짐을 짤거임
//타원 곡선 디지털 서명 알고리즘
const ecdsa = require("elliptic")
const ec = new ecdsa.ec("secp256k1")

const privateKeyLocation = "wallet/"+
(process.env.PRIVATE_KEY || "default");
const privateKeyFile = privateKeyLocation + "/private_key"


function initWallet(){
    if (fs.existsSync(privateKeyFile)){
        console.log("기존 지갑 private key 경로 :" + privateKeyFile)
        return;
    }
    if (!fs.existsSync("wallet/")){
        fs.mkdirSync("wallet/")
    }
    if (!fs.existsSync(privateKeyLocation)){ //wallet/default 파일없다면
        fs.mkdirSync(privateKeyLocation)
        //만들어줘.
       
    }
    if (!fs.existsSync(privateKeyFile)){//프라이빗키없으면
        console.log('주소값 키값을 생성중')
        const newPrivatekey = generatePrivatekey()
        fs.writeFileSync(privateKeyFile, newPrivatekey)
        console.log('개인키 생성이 완료됐습니다')

    }
    const newPrivatekey = generatePrivatekey()
    fs.writeFileSync(privateKeyFile,newPrivatekey)
    console.log("새로운 지갑 생성 private key 경로 :" + privateKeyFile)

}

// initWallet()

//비밀키 생성
function generatePrivatekey(){
    const keyPair = ec.genKeyPair();
    const privateKey = keyPair.getPrivate();
    //16진수로 만들어서 리턴
    return privateKey.toString(16);
}
//비밀키(인증서) 출력하는 함수
function getPrivateKeyFromWallet(){
    //지갑에 만들어놓은 걸 읽을 수 있게 해줌
   const buffer = fs.readFileSync(privateKeyFile,"utf8")
   return buffer.toString();
}
//공개키(지갑주소) 만들기
function getPublicKeyFromWallet(){
    const privateKey = getPrivateKeyFromWallet();
    const key = ec.keyFromPrivate(privateKey, "hex");
    return key.getPublic().encode("hex")
}

module.exports= {getPublicKeyFromWallet,initWallet}

 

 

 

node node httpServer.js

로 실행.

 

 

 

 

 

 

 

1. 암호화 종류

단방향 암호화 : 오직 암호화만 가능

양방향 암호화 : 암호화하고 다시 복호화 가능

 

양방향에 경우 당사자 2명을 제외한 나머지 사람들이 몰라야하므로 

비밀키를 정한다. 하지만 이 비밀키를 알 수 있기 때문에 당사자 2명 각각 서로 다른 키를 가진다. 

비대칭키 암호(공개키,비밀키)

 

 

2. 공개키 알고리즘

 

공개키 알고리즘은 크게 두 가지 방식으로 분류됨

1. 소인수분해 문제를 이용해서 만들어지는 것

2. 이산 로그 문제를 이용해서 만드는 방법 입니다. (타원곡선 )

 

 

 

3. 디지털 서명

 

 

4. ECDSA 알고리즘

타원곡선 암호를 전자서명에 접목시킨 암호 알고르짐

비대칭키 암호에 해당

secp256k1 라는 기준에 맞춰진 방정식 사용

발신자에 의한 서명시 사용되는 개인키와 수신자가 발신자의 서명을 사용하는 공개키 한 쌍을 갖음

 

https://server-engineer.tistory.com/586

https://rosypark.tistory.com/108

 

 

 

 

코드 설명잘해놓음

 

https://velog.io/@nara7875/BlockChain%EC%9E%91%EC%97%85%EC%A6%9D%EB%AA%85%EB%A7%88%EC%9D%B4%EB%8B%9D

728x90
728x90

출처: node.js 교과서

 

웹소켓은 실시간 양방향 데이터 전송을 위한 기술이다. 

http와 다르게 ws라는 프로토콜을 사용한다.

노드에서는 ws나 Socket.IO 같은 패키지를 통해 웹소켓을 사용할 수 있다.

 

 

웹소켓이 나오기 이전에는 http기술을 사용하여 실시간 데이터 전송을 구현했다.

그중 한가지가 폴링polling이라는 방식인데 http가  클라이언트에서 서버로 향하는 단방향 통신이므로 주기적으로 서버에 새로운 업데이트가 있는지 확인하는 요청을 보낸 후 , 있으면 가져오는 단순방식!

 

그러다가 HTML5가 나오면서 웹브라우저와 웹서버가 지속적으로 연결된 라인을 통해 실시간으로 데이터를 주고 받을 수 있는 웹소켓이 등장!

웹소켓이 연결되면 계속 연결된 상태로 있음

따로 업데이트가 있는지 요청을 보낼 필요가 없음

 

업데이트할 내용이 생겼다면 서버에서 바로 클라이언트에 알린다. http프로토콜과 포트를 공유할 수 있어서 다른 포트에 연결할 필요도 없다

 

참고로 

서버센트 이벤트 Server Sent Event (SSE)라는 기술도 등장함

처음에 한번만 연결하면 서버가 클라이언트에 지속적으로 데이터 보냄

웹소켓과 다른점은 클라이언트에서 서버로는 데이터를 보낼 수 없다는 것. 즉 단방향통신

 

웹소켓만이 진정한 양방향 통신

 

 

 

 

 

728x90
728x90

다음과 같은 조건을 거쳐야함.

 

1. 블록구조가 유효한지

2. 현재 블록의 인덱스가 이전 블록의 인덱스보다 1만큼 큰지

3. 이전블록의 해시값과 현재 블록의 이전해시가 같은지

4. 데이터 필드로부터 계산한 머클루트와 블록헤더의 머클루트가 동일한지 

 

이 조건 다 맞으면 올바른 구조체이다.

 

 

1.블록구조가 유효한가

//블록의 각각 타입체크 블록구조 유효한지 체크하는 함수
function isValidBlockStructure(block) {
    return typeof(block.blockheader.version) === 'string'
    && typeof(block.header.index) === 'number'
    && typeof(block.header.previousHash) === 'string'
    && typeof(block.header.timestamp) === 'number'
    && typeof(block.header.merkleRoot) === 'string'
    && typeof(block.body) === 'object'
}
//위 함수를 통해 블록구조의 유효성 검사
function isValidNewBlock(newBlock, previousBlock) {
    if (isValidBlockStructure(newBlock) === false) {
        console.log('Invalid Block Structure')
        return false;
    }
    return true;
}

 

2. 현재 블록의 인덱스가 이전 블록의 인덱스보다 1만큼 큰지

 

//위 함수를 통해 블록구조의 유효성 검사
function isValidNewBlock(newBlock, previousBlock) {
    if (isValidBlockStructure(newBlock) === false) {
        console.log('Invalid Block Structure')
        return false;
        //현재블록이 이전 블록보다 1크지 않으면 false
    } else if (newBlock.header.index !== previousBlock.header.index +1 ){
        console.log('Invalid Index')
        return false;
    }
    return true;
}

3. 이전블록의 해시값과 현재 블록의 이전해시가 같은지

 

나는 새로 만들어서 하는중이라

blockcopy.js 에 블록생성block, 다음블록연결chainedBlock까지 해놨음

여기서 createHash 내보내주기 

 

//이전블록 해시값과 현재 블록해시값의 이전해시가 같은지
//보려고 내보내줘야함 
module.exports = { 
	createHash,
}

이제 현재 코드,

비교해볼 코드에 createHash 가져와야돼

 

(수업때는 checkValidBlock.js 라고 이름지은걸 걍 다시 하면서 checkedBlock.js라고 했닿 )

const {createHash} = require('./blockcopy');

 

//위 함수를 통해 블록구조의 유효성 검사
function isValidNewBlock(newBlock, previousBlock) {
    if (isValidBlockStructure(newBlock) === false) {
        console.log('Invalid Block Structure')
        return false;
    } else if (newBlock.header.index !== previousBlock.header.index +1 ){
        console.log('Invalid Index')
        return false;
        //이전블록해시랑 현재블록의 이전해시가 다르면 false
    } else if (createHash(previousBlock)!==newBlock.header.previousHash) {
        console.log('Invalid previousHash');
        return false;
    }
    return true;
}

4. 데이터 필드로부터 계산한 머클루트와 블록헤더의 머클루트가 동일한지 

 

merkle쓰려면 설치해야돼

 

npm i merkle
const merkle = require("merkle")

....

//위 함수를 통해 블록구조의 유효성 검사
function isValidNewBlock(newBlock, previousBlock) {
    if (isValidBlockStructure(newBlock) === false) {
        console.log('Invalid Block Structure')
        return false;
    } else if (newBlock.header.index !== previousBlock.header.index +1 ){
        console.log('Invalid Index')
        return false;
    } else if (createHash(previousBlock)!==newBlock.header.previousHash) {
        console.log('Invalid previousHash');
        return false;
    } else if (newBlock.body.length === 0 && ('0'.repeat(64) !== newBlock.header.merkleRoot) 
    || newBlock.body.length !== 0 && (merkle("sha256").sync(newBlock.body).root() !==newBlock.header.merkleRoot))
    {
        console.log('Invalid merkleRoot')
        return false
    }
    return true;
}

새블록 body의 길이가 0일 경우 && 머클루트는 '0'.repeat(64)이 아니면

또는 

 

새블록바디 길이가 0이 아닐경우 && 머클루트에있는 정보와  새블록 바디의 루트 정보들이 같지 않으면

false

 

 

5. 새블록추가

chainedBlock.js 하단에 추가

 

나는 blockcopy.js에 추가함요

module.exports = {
	Blocks,
	getLastBlock,
	createHash,
}

checkValidBlock.js 상단에 불러오기

 

나는 checkBlock.js에 넣음

 

const {createHash,Blocks, createHash} = require('./blockcopy');

 

 

 

 

 

 

 

 

검증과정을 마친 블록

 

//검증마친 블록들은 chainedBlock.js의 Blocks배열에 추가한다
function addBlock(newBlock){
    if(isValidNewBlock(newBlock,getLastBlock())){
        Blocks.push(newBlock)
        return true;
    }
    return false;
}

const block = nextBlock(['transaction1'])
addBlock(block)

console.log(block)

 

 

 

blockcopy.js에서의 nextBlock함수 이용해서 

블록생성하고 출력해보기 

 

 

근데 결과에 

 

계속 이게 나와서 

이 콘솔임

 

코드비교해보니까 

blockcopy.js (chainedBlock.js) 에 

index순서 바꾸니까 안뜨네 뭐냐...

blockcopy.js (chained.js)

결과

 

 

 

코드 전체

blockcopy.js

(chainedBlock.js)

더보기
const cryptojs = require('crypto-js')
const fs = require('fs')
const merkle = require('merkle')


class Block{
        constructor(header, body){
		this.header = header
		this.body = body
	}
}

//블록헤더 구조체 선언 : 헤더 구성 요소 나열
class BlockHeader {
	constructor(index, version, previousHash, timestamp, merkleRoot, bit, nonce) {
	  this.index = index
	  this.version = version
	  this.previousHash = previousHash
	  this.timestamp = timestamp
	  this.merkleRoot = merkleRoot
	  this.bit = bit
	  this.nonce = nonce
	}
  }
  

//버전계산하는 함수 
function getVersion(){
	const package = fs.readFileSync("package.json")
	// console.log(JSON.parse(package).version)
	return JSON.parse(package).version

}


//getVersion()

function createGenesisBlock() {
  const index = 0
  const version = getVersion()
  const previousHash = '0'.repeat(64) // 0을 64번 반복
  const timestamp = parseInt(Date.now() / 1000) // 1000 나눈 이유 : 초 단위로 환산하기 위해
  const body = ['Hello block!']
  const tree = merkle('sha256').sync(body)
  const merkleRoot = tree.root() || '0'.repeat(64)
  const bit = 0
  const nonce = 0

  // console.log("version : %s, timestamp : %d, body: %s", version, timestamp, body);
  // console.log("previousHash : %d", previousHash);
  // console.log(tree);
  // console.log("merkleRoot: %s", merkleRoot);

  const header = new BlockHeader(index, version, previousHash, timestamp, merkleRoot, bit, nonce)
  return new Block(header, body)
}

//값넣어서 블록생성

let Blocks = [createGenesisBlock()]

function getBlocks() {
  return Blocks
}
function getLastBlock() {
  return Blocks[Blocks.length - 1]
}



//블록해시 값 구하기
function createHash (data){
	const {version,previousHash,timestamp, merkleRoot, bit, nonce}= data.header
	const blockString = version +previousHash +timestamp+ merkleRoot+ bit+ nonce
	const hash = cryptojs.SHA256(blockString).toString()
	return hash
}



// const block = createGenesisBlock()
// const testHash = createHash(block)
// console.log(testHash)

//다음블록 생성하기 
function nextBlock(bodyData) {
	const prevBlock = getLastBlock()
	const version = getVersion()
	//다음순서니까 하나 추가됨
	const index = prevBlock.header.index + 1
	//createHash함수에 이전블록 정보를 넣어 블록해시값을 구해넣는다.
	const previousHash = createHash(prevBlock)
	const timestamp = parseInt(Date.now() / 1000)
	//블록body부분에 저장될 트랜잭션(거래정보)인 bodyData를
	//merkle몯ㄹ을 사용하여 트랜잭션들의 해시트리를 만들어 tree에 넣어
	const tree = merkle('sha256').sync(bodyData)
	//여기서 최종적으로 구해진 해시값인 머클루트 해시값을 merkleRoot변수에 넣어
	const merkleRoot = tree.root() || '0'.repeat(64)
	const bit = 0
	const nonce = 0

	const header = new BlockHeader
	(index,version,previousHash,timestamp, 
		merkleRoot, bit, nonce)
    return new Block(header,bodyData)

}
//다음블록생성 출력하기
// const block1 = nextBlock(["tranjaction1"])
// console.log(block1)

//addblock함수를 통해 순차적으로 트랜잭션값 전달해 블록생성하고
function addBlock(bodyData) {
	const newBlock = nextBlock([bodyData])
	Blocks.push(newBlock)
  
  }

// addBlock(['transaction1'])
// addBlock(['transaction2'])
// addBlock(['transaction3'])
// addBlock(['transaction4'])
// addBlock(['transaction5'])

// console.log(Blocks);

//이전블록 해시값과 현재 블록해시값의 이전해시가 같은지
//보려고 내보내줘야함 
module.exports = { nextBlock, getLastBlock, createHash, Blocks, getVersion, getBlocks }


// function addBlock(newBlock){

// 	if(isValidNewBlock(newBlock,getLastBlock())){

// 		Blocks.push(newBlock)
// 		return true;
// 	} return false;
// }

 

checkedBlock.js

더보기
const merkle = require("merkle")
const {Blocks, createHash, getLastBlock,nextBlock} = require('./blockcopy');
// const { nextBlock } = require("./chainedBlock");


//블록구조 유효한지
//blockcopy.js에서 만든 블록체인

//블록의 각각 타입체크 블록구조 유효한지 체크하는 함수
function isValidBlockStructure(block) {
  return typeof (block.header.version) === 'string'
    && typeof (block.header.index) === 'number'
    && typeof (block.header.previousHash) === 'string'
    && typeof (block.header.timestamp) === 'number'
    && typeof (block.header.merkleRoot) === 'string'
    && typeof (block.body) === 'object'
}
//위 함수를 통해 블록구조의 유효성 검사
function isValidNewBlock(newBlock, previousBlock) {
    if (isValidBlockStructure(newBlock)===false){
		console.log('Invalid Block Structure');
		return false;
	} else if (newBlock.header.index !== previousBlock.header.index +1 ){
        console.log('Invalid Index')
        return false;
    } else if (createHash(previousBlock)!==newBlock.header.previousHash) {
        console.log('Invalid previousHash');
        return false;
        //블록길이가 0일경우
    } else if (newBlock.body.length === 0 
        //머클루트는길이가 
        && ('0'.repeat(64) !== newBlock.header.merkleRoot) 
    || newBlock.body.length !== 0 && (merkle("sha256").sync(newBlock.body).root() !==newBlock.header.merkleRoot))
    {
        console.log('Invalid merkleRoot')
        return false
    }
    return true;
}

//검증마친 블록들은 chainedBlock.js의 Blocks배열에 추가한다
function addBlock(newBlock){
    if(isValidNewBlock(newBlock,getLastBlock())){
        Blocks.push(newBlock)
        return true;
    }
    return false;
}

const block = nextBlock(['transaction1'])
addBlock(block)

console.log(block)
728x90
728x90

우분투 터미널 환경에서 깃허브 커밋하고 푸시할 때

1. 

git init

현재 폴더를 로컬 저장소로 지정

 

2.

.gitignore 파일 생성

모듈들이 커밋안되게 방지 

안에 (node_modules)

 

3.

git status

로컬 저장소의 현재상태확인

빨간 글씨체로 보여지는 파일목록은 추적되지 않은 파일들(Untracked files)

추적되지 않은 파일이란, 준비 영역이나 로컬 저장소에 한번이라도 add되거나 commit되지 않은 파일을 말한다.

반대로 추적 상태인 파일들(Tracked files)은 최소한 한번은 git add 명령을 통해 준비 영역에 포함되거나 commit을 통해 로컬 저장소에 저장된 파일이다.

4.

git add .

git add는 특정 파일만 업로드하고자 할 때 사용한다.

 

git add "파일명"



 

5. 로컬 저장소에 최종저장하는 단계

 git commit -m "메세지"

 

6. 로컬 저장소와 원격저장소를 연결

git remote add origin Git Repository 주소

*origin은 별칭이다.

 

7. 별칭내역을 확인

origin의 별칭으로 등록된 원격 저장소를 확인할 수 있다.

 

 git remote -v

 

 

8. 로컬 저장소의 파일들을 원격 저장소로 올린다.

 

git push origin master




 

 

이렇게 나옴

remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.
remote: Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information.
fatal: Authentication failed for 'https://github.com/jsoyun/blockchain.git/'

 

그래서 찾아보니까 

 

Settings / Developer settings/Personal access tokens / Generate new token / Token 설정

으로 들어가서

 

토큰 비번을 만들어서 

비번에 넣어주니까 되더라 

 

 

 

 

 

출처:

 

에러시 이거

https://hyeo-noo.tistory.com/184

 

[Mac] GitHub push token 오류 해결

Github 오류 7.29일 새벽 갑자기 git push가 안 되는 현상을 겪었다. 오류의 첫 줄이 무슨 말이냐면 Password 인증방식이 일시적으로 brownout(shutdown?)되었다. Password 대신에 personal access token을 사용..

hyeo-noo.tistory.com

https://shxrecord.tistory.com/179 [두-번째저장소]

https://codecoco.tistory.com/74?category=512233 

728x90
728x90

chainedBlock.js  이라 이름지음요

 

이전 글에서 블록하나를 생성했으니 여러 블록을 이어서 블록체인 만들어보기

코드는 수업때 했지만 이번에도 설명을 보면서 고대로 정리했음 https://berrypjh.tistory.com/50

설명은 똑같고 내가 헤맨거 좀좀따리 추가됨

 

(리눅스 우분투에서 작업중)

 

블록해시 값 구하기

....이전과 같음

class BlockHeader{
        constructor(version,index, previousHash, timestamp, merkleRoot, bit, nonce){
	     this.version = version
		//index 값 넣기
     	 this.index = index
	     this.previousHash = previousHash
	     this.timetamp = timestamp
	     this.merkleRoot = merkleRoot
	     this.bit = bit
	     this.nonce = nonce
		

	}
}

//버전계산하는 함수 
function getVersion(){
...

}

function createGenesisBlock(){
	const version = getVersion()
	//index 값 넣기
	const index = 0
	const previousHash = '0'.repeat(64)
	const timestamp = parseInt(Date.now()/1000)
	const body = ['hello block']
	const tree = merkle('sha256').sync(body)
	const merkleRoot = tree.root() || '0'.repeat(64)
	const bit = 0
	const nonce = 0

...     
	//헤더에 대입
	const header = new BlockHeader(version, index, previousHash, timestamp, merkleRoot, bit,nonce)
    return new Block(header, body)

}
//값넣어서 블록생성
const block = createGenesisBlock()
console.log(block)

 

1) index 값 넣어서 이후에 만들 블록체인 순서를 확인할 수 있게 한다.

(아까 index를 선언만 하고 BlockHeader constructor 구조에 안넣고 헤더에 대입에도 안넣어서 안됐었음

게다가 뒤에 선언하는거랑 넣어준 순서다르면 안되더라...)

 

 

2) 블록체인 불러오기 

//여러개 들어갈 수 있는 배열로 Blocks를 만들어줌 
let Blocks = [createGenesisBlock()]


//현재 있는 블록들을 다 리턴해주는 함수
function getBlocks(){
	return Blocks
}

function getLastBlock(){
	//길이 1이니까 1-1 =0 즉 첫번째배열 불러와 
	return Blocks[Blocks.length - 1]

}

블록체인의 블록들을 넣어줄 Blocks배열을 만들고 첫번째 블록을 생성하는 함수인 createGenesisBlock함수를 해당 배열에 미리 넣어둔다.

 

3)블록해시값 구하기

 

//블록해시 값 구하기
//data에는 블록이 들어오는거임, 이블록을 가지고 해시값을 만들어내는 것임
function createHash (data){
	const {version,previousHash,timestamp, merkleRoot, bit, nonce}= data.header
	const blockString = version +previousHash +timestamp+ merkleRoot+ bit+ nonce
	const hash = crypto.js.SHA256(blockString).toString()
	return hash
}

블록헤더 안에 든 정보들 (version 등)의 합산 정보를 구한후 SHA256으로 변환하면 블록의 블록해시값을 구할 수 있다.

 

crypto.js 쓰려면 

const cryptojs =require('crypto-js')

이거 추가해야될거야

 

node 스크립트이름

 

 

다음블록 생성하기

//다음블록 생성하기 
function nextBlock(bodyData) {
	const prevBlock = getLastBlock()
}

이전 블록의 정보(가장 최신 블록 정보)를 getLastBlock함수를 이용해서 가져오고 prevBlock에 넣어둔다.

//다음블록 생성하기 
function nextBlock(bodyData) {
	const prevBlock = getLastBlock()
	const version = getVersion()
	//다음순서니까 하나 추가됨
	const index = prevBlock.header.index +1
	//createHash함수에 이전블록 정보를 넣어 블록해시값을 구해넣는다.
	const previousHash = createHash(prevBlock)
	const timestamp = parseInt(Date.now()/1000)
	//블록body부분에 저장될 트랜잭션(거래정보)인 bodyData를
	//merkle몯ㄹ을 사용하여 트랜잭션들의 해시트리를 만들어 tree에 넣어
	const tree = merkle('sha256').sync(bodyData)
	//여기서 최종적으로 구해진 해시값인 머클루트 해시값을 merkleRoot변수에 넣어
	const merkleRoot = tree.root() || '0'.repeat(64)
	const bit = 0
	const nonce = 0

const header = new BlockHeader(index,version,previousHash,timestamp, merkleRoot, bit, nonce)
     return new Block(header,bodyData)

}

머클루트 값을 통해 단일 블록내에 존재하는 트랜잭션의 무결성을 검증할 수 있고,

머클루트 값을 이용해 블록의 해시값을 생성했기 때문에 블록의 해시의 무결성도 함께 검증할 수 있다. 

 

 

두번째 블록 생성하고 출력해보기 

//다음블록 생성하기 
function nextBlock(bodyData) {
	const prevBlock = getLastBlock()
	const version = getVersion()
	//다음순서니까 하나 추가됨
	const index = prevBlock.header.index +1
	//createHash함수에 이전블록 정보를 넣어 블록해시값을 구해넣는다.
	const previousHash = createHash(prevBlock)
	const timestamp = parseInt(Date.now()/1000)
	//블록body부분에 저장될 트랜잭션(거래정보)인 bodyData를
	//merkle몯ㄹ을 사용하여 트랜잭션들의 해시트리를 만들어 tree에 넣어
	const tree = merkle('sha256').sync(bodyData)
	//여기서 최종적으로 구해진 해시값인 머클루트 해시값을 merkleRoot변수에 넣어
	const merkleRoot = tree.root() || '0'.repeat(64)
	const bit = 0
	const nonce = 0

	const header = new BlockHeader(version,index,previousHash,timestamp, merkleRoot, bit, nonce)
    return new Block(header,bodyData)

}
//다음블록생성 출력하기
const block1 = nextBlock(["tranjaction1"])
console.log(block1)

인덱스1 이면 배열은 0부터 시작하니까 두번째 맞겠지..?

트랜잭션 값이 'tranjaction1'인 두번째 블록 생성됨 확인 

 

 

블록체인에 넣기

 

function addBlock(bodyData) {
	const newBlock = nextBlock(bodyData)
	Blocks.push(newBlock)
}

addBlock(['transaction1'])
addBlock(['transaction2'])
addBlock(['transaction3'])
addBlock(['transaction4'])
addBlock(['transaction5'])

위처럼 여러 트랜잭션을 순차적으로 addBlock함수를 통해 트랜잭션 값을 전달하여 블록을 생성하고 Blocks배열에 넣어보기

 

최종결과 출력하기

console.log(Blocks);

 

결과

 

전체 코드

더보기
const fs = require('fs')
const merkle = require('merkle')
const cryptojs = require('crypto-js')

class Block{
        constructor(header, body){
		this.header = header
		this.body = body
	}
}

class BlockHeader{
        constructor(version,index, previousHash, timestamp, merkleRoot, bit, nonce){
	     this.version = version
		//index 값 넣기
     	 this.index = index
	     this.previousHash = previousHash
	     this.timetamp = timestamp
	     this.merkleRoot = merkleRoot
	     this.bit = bit
	     this.nonce = nonce
		

	}
}

//버전계산하는 함수 
function getVersion(){
	const package = fs.readFileSync("package.json")
	console.log(JSON.parse(package).version)
	return JSON.parse(package).version

}


//getVersion()

function createGenesisBlock(){
	const version = getVersion()
	//index 값 넣기
	const index = 0
	const previousHash = '0'.repeat(64)
	const timestamp = parseInt(Date.now()/1000)
	const body = ['hello block']
	const tree = merkle('sha256').sync(body)
	const merkleRoot = tree.root() || '0'.repeat(64)
	const bit = 0
	const nonce = 0

	// console.log("version : %s, timestamp: %d, body : %s",version,timestamp,body)
	// console.log("previousHash : %d", previousHash);
	// console.log("tree :")
	// // console.log(tree)
	// console.log("merkleRoot : %s", merkleRoot);
	// console.log("merkleRoot : %s", merkleRoot.toString('hex'));
     
	//헤더에 대입
	const header = new BlockHeader(version, index, previousHash, timestamp, merkleRoot, bit,nonce)
    return new Block(header, body)

}
//값넣어서 블록생성
let Blocks = [createGenesisBlock()]
function getBlocks(){
	return Blocks
}
function getLastBlock(){
	return Blocks[Blocks.length -1]
}


//블록해시 값 구하기
function createHash (data){
	const {version,previousHash,timestamp, merkleRoot, bit, nonce}= data.header
	const blockString = version +previousHash +timestamp+ merkleRoot+ bit+ nonce
	const hash = cryptojs.SHA256(blockString).toString()
	return hash
}

// const block = createGenesisBlock()
// const testHash = createHash(block)
// console.log(testHash)

//다음블록 생성하기 
function nextBlock(bodyData) {
	const prevBlock = getLastBlock()
	const version = getVersion()
	//다음순서니까 하나 추가됨
	const index = prevBlock.header.index +1
	//createHash함수에 이전블록 정보를 넣어 블록해시값을 구해넣는다.
	const previousHash = createHash(prevBlock)
	const timestamp = parseInt(Date.now()/1000)
	//블록body부분에 저장될 트랜잭션(거래정보)인 bodyData를
	//merkle몯ㄹ을 사용하여 트랜잭션들의 해시트리를 만들어 tree에 넣어
	const tree = merkle('sha256').sync(bodyData)
	//여기서 최종적으로 구해진 해시값인 머클루트 해시값을 merkleRoot변수에 넣어
	const merkleRoot = tree.root() || '0'.repeat(64)
	const bit = 0
	const nonce = 0

	const header = new BlockHeader(version,index,previousHash,timestamp, merkleRoot, bit, nonce)
    return new Block(header,bodyData)

}
//다음블록생성 출력하기
const block1 = nextBlock(["tranjaction1"])
// console.log(block1)

//addblock함수를 통해 순차적으로 트랜잭션값전달해 블록생성하고
function addBlock(bodyData) {
	const newBlock = nextBlock(bodyData)
	Blocks.push(newBlock)
}

addBlock(['transaction1'])
addBlock(['transaction2'])
addBlock(['transaction3'])
addBlock(['transaction4'])
addBlock(['transaction5'])

console.log(Blocks);
728x90
728x90

이론 출처: https://steemit.com/kr/@yahweh87/3

코드설명:https://berrypjh.tistory.com/50

 

블록체인에서 사용되는 '블록' 일정 시간마다(비트코인의 기준으로 10분에 한 번씩 생성됩니다.)

 여러 건의 거래내역을 하나의 블록으로 묶어 기존에 생성된 블록에 체인처럼 계속적으로 연결하는 데이터 구조를 의미합니다. 

 

 

블록은 블록체인의 원소 개념으로, 다수의 거래 정보의 묶음을 의미합니다.

블록에는 블록의 이름이 있는데 Height(높이)라는 용어로 표현되고 있습니다.

한 칸 한 칸 쌓아나가 탑의 형태로 구성된다고 생각하여 Height(높이)라는 말을 쓴다고 합니다.(깊이라고 이해해도 될듯)

하지만 이 높이는 정확한 블록의 이름이 아닙니다. 

블록의 정확한 이름은 TXID라 불리는 블록의 해시값입니다. 이 블록의 해시값은 블록의 헤더 정보(블록의 버전, 이전블록해시,머클루트,타임,bits,논스 정보)를 모두 합산한 후 SHA256으로 변환된 값입니다.

bits : 난이도 해시 목표값을 의미하는 지표

nonce: 블록을 만드는 과정에서 해시값을 구할 때 필요한 재료 역할을 수행한다.

블록의 구성요소

여러 요소들이 있지만

크게 블록 헤더블록 바디로 나눌 수 있다.

블록 하나 만들기

(리눅스 우분투에서 코드 작성중)

<block.js>

lass Block{
        constructor(header, body){
		this.header = header
		this.body = body
	}
}

class BlockHeader{
        constructor(version, previousHash, timestamp, merkleRoot, bit, nonce){
	     this.version = version
	     this.previousHash = previousHash
	     this.timetamp = timestamp
	     this.merkleRoot = merkleRoot
	     this.bit = bit
	     this.nonce = nonce

	}
}

header와 body가 들어간 block클래스를 만들고 블록의 header class도 만들어준다.

npm init

버전과 모듈설치확인 위해서 package.json 파일 만들고 fs불러서 버전표시해보자

const fs = require('fs')

//버전계산하는 함수 
function getVersion(){
	const package = fs.readFileSync("package.json")
	console.log(JSON.parse(package).version)
	return JSON.parse(package).version

}

 

 

# node block.js

 

첫번째 block값 대입한다

function createGenesisBlock(){
	const version = getVersion()
	const previousHash = '0'.repeat(64)
	const timestamp = parseInt(Date.now()/1000)

}

 

version은 getVersion에서 나온 값을 대입한다.

previousHash는 이전 블록이 없는 첫번째 블록이므로 64비트 '0'을 대입

timestamp는 Date써서 현재 시간 넣어두기

 

머클리루트 값을 넣기 위해 설치

 

npm i merkle

 

function createGenesisBlock(){
	const version = getVersion()
	const previousHash = '0'.repeat(64)
	const timestamp = parseInt(Date.now()/1000)
	const body = ['hello block']
	const tree = merkle('sha256').sync(body)
	const merkleRoot = tree.root() || '0'.repeat(64)
	const bit = 0
	const nonce = 0

	console.log("version : %s, timestamp: %d, body : %s",version,timestamp,body)
	console.log("previousHash : %d", previousHash);
	console.log("tree :")
	// console.log(tree)
	console.log("merkleRoot : %s", merkleRoot);
	console.log("merkleRoot : %s", merkleRoot.toString('hex'));

	// const header = new BlockHeader(version, previousHash, timestamp, merkleRoot, bit,nonce)
	// return new Block(header, body)

}

해당 모듈 설치 후 body에 들어갈 트랜잭션(거래내역)인 첫 번째 데이터로 hello block을 넣음

나머지는 0대입하고 만들어보고 실행해보기

 

node block.js

하면

(아까는 merkleRoot 안나왔는데 %d 여서 그랬음 %s 이게 string값 불러오는건가보다 둘이 똑같이 뜨네)

 

 

첫번째 블록 생성하기

function createGenesisBlock(){
	const version = getVersion()
	const previousHash = '0'.repeat(64)
	const timestamp = parseInt(Date.now()/1000)
	const body = ['hello block']
	const tree = merkle('sha256').sync(body)
	const merkleRoot = tree.root() || '0'.repeat(64)
	const bit = 0
	const nonce = 0

	console.log("version : %s, timestamp: %d, body : %s",version,timestamp,body)
	console.log("previousHash : %d", previousHash);
	console.log("tree :")
	// console.log(tree)
	console.log("merkleRoot : %s", merkleRoot);
	console.log("merkleRoot : %s", merkleRoot.toString('hex'));
     
	//헤더에 대입
	const header = new BlockHeader(version, previousHash, timestamp, merkleRoot, bit,nonce)
    return new Block(header, body)

}
//값넣어서 블록생성
const block = createGenesisBlock()
console.log(block)

위에 대입한 결과를 BlockHeader class로 정보를 전달하고 

블록헤더와 바디를 Block class에 전달하여 첫번째 블록을 생성하였다.

 

node block.js  로 실행결과보기

 

block.js 전체코드는 이와같다.

더보기
const fs = require('fs')
const merkle = require('merkle')

class Block{
        constructor(header, body){
		this.header = header
		this.body = body
	}
}

class BlockHeader{
        constructor(version, previousHash, timestamp, merkleRoot, bit, nonce){
	     this.version = version
	     this.previousHash = previousHash
	     this.timetamp = timestamp
	     this.merkleRoot = merkleRoot
	     this.bit = bit
	     this.nonce = nonce

	}
}

//버전계산하는 함수 
function getVersion(){
	const package = fs.readFileSync("package.json")
	console.log(JSON.parse(package).version)
	return JSON.parse(package).version

}


//getVersion()

function createGenesisBlock(){
	const version = getVersion()
	const previousHash = '0'.repeat(64)
	const timestamp = parseInt(Date.now()/1000)
	const body = ['hello block']
	const tree = merkle('sha256').sync(body)
	const merkleRoot = tree.root() || '0'.repeat(64)
	const bit = 0
	const nonce = 0

	console.log("version : %s, timestamp: %d, body : %s",version,timestamp,body)
	console.log("previousHash : %d", previousHash);
	console.log("tree :")
	// console.log(tree)
	console.log("merkleRoot : %s", merkleRoot);
	console.log("merkleRoot : %s", merkleRoot.toString('hex'));
     
	//헤더에 대입
	const header = new BlockHeader(version, previousHash, timestamp, merkleRoot, bit,nonce)
    return new Block(header, body)

}
//값넣어서 블록생성
const block = createGenesisBlock()
console.log(block)

 

 

 

 

 

728x90
728x90

Hash

sha256

단방향 암호화, 자리수 64자리로 고정됨

 

해시함수 설명:

더보기

해시함수를 이용한다면 어떤 길이의 입력값이라도 256비트의 고정된 결과값을 출력할 것이고

입력값의 아주 일부만 변경되어도 전혀 다른 값이 출력되는 특징 때문에 데이터가 변경되었는지 쉽게 확인할 수 있습니다.

추가적으로 해시함수는 입력된 값이 같을 경우 항상 같은 결과 값을 출력해야합니다.

https://steemit.com/kr/@yahweh87/2)

 

머클트리 Merkle tree, 머클 루트 Merkle root

데이터가 위변조 되었는지 효율적으로 확인하기 위한 용도로 사용됨

자바스크립트에서 merkletreejs를 이용해 사용할 수 있다.

https://blockone.tistory.com/11 -Merkle tree

더보기

출처 : https://blockone.tistory.com/11

머클트리 Merkle tree

해시트리 라고도 한다. 여러 블록으로 나뉘어 있는 데이터를 전송할 때 데이터가 변조되지 않았음  보증하는 용도로 쓰인다. 특히 p2p네트워크에서 전송받는 데이터에 오류가 있거나 외부로부터 조작이 있었는지 검증하는 용로도로 쓰인다.

블록체인에서는 블록에 포함된 거래 데이터를 요약해 트리 형태로 만들게 되는데 해시함수를 활용해 두개의 거래 데이터를 하나의 데이터로 묶음으로써 용량을 절약할 수 있다.

머클 루트 

블록에 들어있는 모든 거래내역을 요약한 데이터로 최소한의 정보로 인증할 수 있도록 도와준다.

개별 거래에 대한 트랜잭션을 검증하는 기능을 수행하는 노드(라이트노드)에 대해서는 중요한 데이터만 갖고 있게 한다. 외부에서 다른 블록의 거래내역을 조작하면 머클루트를 대조하여 비교하게 된다. 가장 밑단에 있는 거래를 제외한 나머지내역을 두개씩 짝지어 해시값을 얻고 또 그 해시끼리 짝지어 암호화하는 식이다. 이렇게 모든 거래 내역에 해시값을 얻는 과정을 거듭하여 나무 모형으로 만들면 머클트리가 된다. 결국 머클트리 그 자체가 해시로 이루어져 있다. 하나의 트랜잭션이 변조되면 머클루트까지 모든 값이 바뀌게 되는 쇄도효과가 일어난다.

 

 

합의 알고리즘

-작업증명Proof of Work

-지분증명 Proof of Stake

728x90
728x90

계속 헷갈리는게 root계정인지 일반계정인지 sudo su가 슈퍼관리자로 가능하대서 다되는구나 이생각

무지성으로 따라해서 ㅎㅎ

 

터미널에서 하던걸 vscode에서 해볼까했는데 저장안됨

어 저번엔 됐었는데

 

이유는 우분투 연결한 vscode는 

일반계정으로 열리는 거임

 

근데 터미널에서는 sudo su- 슈퍼계정 root로 파일들 만들잖아

그 파일이 일반계정으로 열리는 vscode에서는 수정이 안되는거임 권한이 없어서

 

그동안 일반계정으로 했다가 root계정으로 했다가 막한 흔적들

 

일반계정으로 파일 만들어보니까

vscode에서도 수정잘될 수 있는거 확인.

 

 

왜 파일만들때 sudo su-로 root계정에 들어가서 작업하는거지?

root에서만 할 수 있는 작업들이 있다 하더라고

 

728x90
728x90

 

 

분산되어 저장한다는 것은 탈중앙화를 의미

P2P(Peer to Peer) 네트워크를 통해서 관리되는 분산데이터베이스에 의한 형태

분산처리와 암호화

블록체인 네트워크에 연결된 여러 컴퓨터(노드)에 저장 및 보관하는 기술

 

블록들을 체인 형태로 묶은 형태

블록들이 형성된 후 시간의 흐름에 따라 순차적으로 연결된 '사슬(체인)'의 구조를 가지게 된다

 

특장점

 

  • 분산저장 (기존거래방식은 데이터를 위,변조하기 위해서 중앙서버를 공격)
  • 여러 명이 동일한 데이터를 저장
  • 블록체인 네트워크를 위,변조하기 위해서는 참여자(노드)의 거래 데이터를 모두 공격해야하기 때문에 사실상 해킹이 불가능
  • 중앙관리자 불필요(중앙기관,관리자 없어도 다수가 데이터를 저장,증명할 수 있기 때문에 탈중앙화가 가능)

 

블록체인의 기술 활용

  • 금융거래
  • 개인의료정보
  • 영상 또는 이미지, 콘텐츠
  • 부동상
  • 의료
  • 인적자원

 

 

블록체인의 기술

  • 해쉬(Hash) 함수를 사용
  • 스마트계약을 활용

블록체인 동작원리

  • 하나의 새로운 블록을 구성한 경우, 이전부터 이어져 내려오던 블록체인의 맨끝에 이 새로운 블록을 연결
  • 새로 구성한 블록의 이름에 해당하는 해시를 찾아내는 일(목표 값보다 작아야한다는 조건을 충족해야함.)

예시)목표 해시 값: 00ff32라고 가정

새로 만든 블록의 해시값: (블록생성에 실패)

새로 찾아낸 해시값: 00c3b1(새로운 블록의 생성에 성공)

 

 

728x90

+ Recent posts