본문 바로가기
ios 뽀개기/swift-blockchain

스위프트로 배우는 블록체인 - 탈중앙화 구현

by 인생여희 2018. 6. 2.
반응형

스위프트로 배우는 블록체인 - 탈중앙화 구현


노드모듈생성

지금까지는 하나의 네트워크에서 블록체인이 어떻게 작동하는지 알아보았습니다. 지금부터는 여러개의 노드를 만들어서 탈중앙화 개념을 구현해 보도록 하겠습니다. model.swift에 새로운 노드를 생성할 클래스를 아래와 같이 작성해 줍니다.

//새로운 노드 생성 클래스

class BlockchainNode : Codable {

    var address : String

    init(address : String) {

        self.address = address

    }

}


아래에 이이서 class Blockchain 부분에 아래에 위에서 만든 노드 데이터를 컨트롤할 변수와 추가할 함수를 만들어 준다.

//체인 구조체

class Blockchain : Codable {

    //블록이 배열형태로 저장됨

    private (set) var blocks : [Block] = [Block]()

   

    //추가! 블록체인 데이터 구조에 블록체인 배열 값을 가지는 변수 생성

    private (set) var nodes : [BlockchainNode] = [BlockchainNode]()


    //추가! 블록체인 데이터 구조에 노드를 추가하는 함수

    func addNode(_ node : BlockchainNode){

        self.nodes.append(node)


}



마지막으로 이번에는 제일 위에서 만든 BlockchainNode 클래스에 아래와 같이 코드를 추가해 준다. 블록체인컨트롤.swift에서  웹브라우저로 넘어오는 request 데이터로 이 클래스를 초기화 해주기 위해서 아래 코드를 추가한다.

//새로운 노드 생성 클래스

class BlockchainNode : Codable {

    var address : String

    

    //BlockchainController.swift 에서 request 로 넘어오는 데이터로 초기화 하기 위한 초기화 함수

    init?(request : Request){

        

        guard let address = request.data["address"]?.string else {

            return nil

        }

        self.address = address

    }

    

    init(address : String) {

        self.address = address

    }

}


노드등록

노드를 생성하는 함수를 만들었으니 이번에는 생성된 노드를 등록하는 함수를 구현해보겠습니다. BlockchainService 클래스로 가서 아래 코드를 추가해준다. //추가! 부분이다.

class BlockchainService {

    

    //체인배열 변수

    private (set) var blockchain : Blockchain!

    

    //제네시스 블럭 초기화=

    init() {

        self.blockchain = Blockchain(genesisBlock: Block())

        

    }

    

    //추가! 생성한 노드를 블록체인에 추가하는 함수

    func registerNode(_ node : BlockchainNode){

            self.blockchain.addNode(node)

}


이어서 이제 BlockchainController.swift로 와서 func setupRoutes(){} 함수 부분에 웹브라우저를 통해서 노드를 등록하고, 등록한 노드를 확인해주는 로직을 작성해보겠다. 아래 소스 코드 참고.

    private func setupRoutes(){

        

        //노드 등록

        self.drop.post("/nodes/register"){ request in

            if let blockchainNode = BlockchainNode(request: request){

                self.blockchainService.registerNode(blockchainNode)

            }

            return try JSONEncoder().encode(["msg":"노드 등록 성공"])

        }

        

        //노드 확인

        self.drop.get("/nodes"){request in

            let nodes = self.blockchainService.blockchain.nodes

            return try JSONEncoder().encode(nodes)

}

테스트

위에 소스가 잘 작동을 하는지 포스트맨을 통해서 확인해보자~


등록된노드 확인 (8080,8088 등 여러개 등록해서 확인해보자)



여러 노드에서 마이닝 구현


vapor 프레임워크를 통해서 여러 포트의 서버를 등록해보겠다. 터미널을 열고 작업폴더에 위치한다음에 

vapor run --port=8080, vapor run --port=8090, vapor run --port=8010 등 여러 서버가 가동되게 한다. 그리고 반드시 웹브라우저에서 확인 해야 한다.


마지막 구현

모든 노드들이 데이터를 공유하게 하기 위한 코드를 작성해보자. 일단 Blockchain 클래스에 blocks 변수 앞에 private 키워드 제거해준다.

//체인 구조체

class Blockchain : Codable {

    //블록이 배열형태로 저장됨

    var blocks : [Block] = [Block]()


service 부분에 아래 함수 추가

    func resolve(completion : @escaping (Blockchain) -> ()){

        

        let nodes = self.blockchain.nodes

        for node in nodes{

            let url = URL(string: "http://\(node.address)/blockchain")!

            URLSession.shared.dataTask(with: url){ data,_, _ in

                if let data = data{

                    let blockchain = try! JSONDecoder().decode(Blockchain.self, from: data)

                    if self.blockchain.blocks.count > blockchain.blocks.count{

                        completion(self.blockchain)

                    }else{

                        self.blockchain.blocks = blockchain.blocks

                        completion(blockchain)

                    }

                }

            }.resume()

        }

}

controller 부분에 아래 함수 추가

    private func setupRoutes(){

        self.drop.get("/nodes/resolve"){request in

            return try Response.async{

                portal in

                self.blockchainService.resolve(completion: { (blockchain) in

                    let blockchain = try! JSONEncoder().encode(blockchain)

                    portal.close(with: blockchain.makeResponse())

                })

            }

}


테스트

post맨을 열어서 한번더 테스트를 해보자.







반응형

댓글