제퍼넷 로고

스팀 블록 체인의 토큰 !!!

시간

그리고 직접 만드는 방법!

다음에 대한 튜토리얼 steem-state.

저장소

https://github.com/nicholas-2/steem-state

무엇을 배울 것인가?

  • 다음을 사용하여 토큰 DApp을 생성하는 방법을 배웁니다. steem-statesteem-transact
  • 다음을 사용하여 DApp 개발 뒤에 숨은 패턴을 배우게 됩니다. steem-statesteem-transact
  • 소프트 합의에 대해 자세히 알아보고 다음을 사용하여 향후 DApp을 설계할 수 있습니다. steem-state 보다 분산된 방식으로.

요구조건 니즈

이 튜토리얼을 따르기 위해 사용자에게 필요한 요구 사항을 명시하십시오.

  • nodejs와 npm을 컴퓨터에 설치하고 각각에 대한 기본적인 이해(예: 콜백이란 무엇입니까?)
  • 완료했습니다 프로젝트 README의 메시징 앱 튜토리얼.
  • 거래를 생성하는 데 사용할 Steem 계정이 있어야 합니다.
  • 암호화폐/블록체인과 Steem에 대한 기본적인 이해가 있어야 합니다.

난이도 중급

튜토리얼

이 튜토리얼에서는 Ethereum의 ERC20 스마트 계약과 유사하게 작동하는 DApp을 구축할 것입니다. Steem 네트워크 위에 있는 토큰입니다. 또한 DApp을 구축할 때 DApp과 상호 작용하기 위한 CLI(명령줄 인터페이스)도 구축할 것입니다.

먼저 새 항목을 만듭니다. npm 우리가 사용할 패키지가 포함된 프로젝트:

mkdir basic-token
cd basic-token
npm init
npm install dsteem steem-state steem-transact

그런 다음 튜토리얼 전체에 걸쳐 프로그래밍할 index.js를 만듭니다. 먼저 종속성을 가져오고 설정합니다. readline CLI에 사용하려면:

var steem = require('dsteem');
var steemState = require('steem-state');
var steemTransact = require('steem-transact');
var readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout
});

그런 다음 초기화합니다. state 변하기 쉬운. 이는 마지막 작업이 처리된 이후 현재 상태로 작동합니다. 지금은 토큰 소유를 시작할 사람을 정의할 수 있는 제네시스 상태로 설정되어 있습니다. 나는 토큰의 소유자를 나 자신으로 설정하고 @ausbitbank, 처음으로 주연을 맡은 사람 steem-state 저장소 및 제공 @ausbitbank 토큰 10개. 다음으로 사용자 이름과 키에 대한 몇 가지 변수를 생성하고(이 애플리케이션을 프로덕션에 배포한 경우 사용자에게 사용자 이름과 키를 묻는 메시지를 표시할 가능성이 높음) dsteem 고객. 마지막으로 전역 속성(메시징 앱 튜토리얼에서와 같이 생성된 마지막 블록을 읽는 데 사용할)을 가져와서 다음과 같은 함수로 보냅니다. startApp, 다음에 생성하겠습니다.

var state = { balances: { shredz7: 990, ausbitbank: 10 }
} var username = 'your-username-here';
var key = 'your-private-posting-key-here'; var client = new steem.Client('https://api.steemit.com'); client.database.getDynamicGlobalProperties().then(startApp);

선언하자 startApp 함수, 이전 동적 전역 속성을 취하고 빈 상태 프로세서를 시작합니다(나중에 채울 것입니다). 여기서 접두사는 다음과 같습니다. first_steem_token_. 원하는 대로 설정할 수 있습니다. 접두사가 DApp에 고유한지 확인하세요. 또한 블록 스트리밍 모드를 '되돌릴 수 없음'으로 설정하여 각 블록을 확인하는 데 시간이 더 걸리지만 완전히 안전합니다.

function startApp(dynamicGlobalProperties) { var processor = steemState(client, steem, dynamicGlobalProperties.head_block_number, 10, 'first_steem_token_', 'irreversible'); processor.start();
}

다음 단계는 CLI의 첫 번째 부분을 생성하는 것입니다( readline 패키지), 모든 사용자의 잔액을 볼 수 있도록(이것을 안에 넣으세요) startApp). 아래 코드는 명령이 실행될 경우 balance [user] 입력하면 [사용자]가 소유한 토큰의 양이 인쇄됩니다. 또한 명령의 형식이 올바르지 않으면 "잘못된 명령"이 인쇄됩니다.

rl.on('line', function(data) { var split = data.split(' '); if(split[0] === 'balance') { var user = split[1]; var balance = state.balances[user]; if(balance === undefined) { balance = 0; } console.log(user, 'has', balance, 'tokens'); } else { console.log('Invalid command.'); }
}

이제 우리는 CLI의 기반과 Steem 블록체인과의 인터페이스를 갖췄습니다. 지금까지의 코드는 다음과 같습니다.

var steem = require('dsteem');
var steemState = require('steem-state');
var steemTransact = require('steem-transact');
var readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout
}); var state = { balances: { shredz7: 990, ausbitbank: 10 }
} var username = 'your-username-here';
var key = 'your-private-posting-key-here'; var client = new steem.Client('https://api.steemit.com'); function startApp(dynamicGlobalProperties) { var processor = steemState(client, steem, dynamicGlobalProperties.head_block_number, 10, 'first_steem_token_'); processor.start(); rl.on('line', function(data) { var split = data.split(' '); if(split[0] === 'balance') { var user = split[1]; var balance = state.balances[user]; if(balance === undefined) { balance = 0; } console.log(user, 'has', balance, 'tokens'); } else { console.log('Invalid command.'); } });
} client.database.getDynamicGlobalProperties().then(startApp);

이 스크립트를 실행하면 특정 사용자의 잔액을 확인할 수 있고 오류가 없어야 합니다. 멋진!

이제 실제로 DApp을 정의해야 합니다. 프로세서가 생성된 후 시작되기 전에 코드를 입력하여 프로세서를 처리할 수 있습니다. send 트랜잭션(이 예에서 사용할 유일한 트랜잭션). 형식은 send 거래는 다음과 같습니다:

{ to, // The user to send the tokens to amount // The amount of tokens to send
}

이 정의에서 흥미로운 점은 트랜잭션이 유효한지 여부를 확인하는 매우 긴 if 문을 포함하는 방법입니다. 다음을 순서대로 확인합니다.

수신자가 정의되지 않았는지, 수신자가 문자열인지, 전송할 금액이 숫자인지, 전송할 금액이 정수인지 여부(부동 소수점을 사용하면 합의가 깨질 수 있음, 참조) 이 페이지), 보낼 금액이 0보다 큰지(음수 금액을 보내면 사용자가 서로 훔칠 수 있습니다!), from 계정에 잔액 항목이 있고(잔고가 0보다 큼) from 계정에 더 많은 금액이 있는지 여부입니다. 보내려는 것보다 토큰이 많습니다.

다음으로 항목을 추가합니다. state.balances 사용자에게 아직 없는 경우 JSON을 생성한 다음 각 사용자의 잔액을 업데이트하여 작업을 적용합니다.

processor.on('send', function(json, from) { if(json.to && typeof json.to === 'string' && typeof json.amount === 'number' && (json.amount | 0) === json.amount && json.amount >= 0 && state.balances[from] && state.balances[from] >= json.amount) { console.log('Send occurred from', from, 'to', json.to, 'of', json.amount, 'tokens.') if(state.balances[json.to] === undefined) { state.balances[json.to] = 0; } state.balances[json.to] += json.amount; state.balances[from] -= json.amount; } else { console.log('Invalid send operation from', from) } })

이제 우리는 이것을 가지고 있습니다 send 작업이 정의되면 CLI 명령을 생성하여 실제로 전송 작업을 완료하고 새 작업을 선언할 수도 있습니다. transactor 사용 steem-transact (여기에 토큰의 올바른 접두사를 추가했는지 확인하세요). 이 명령은 다음 형식을 사용합니다. send [user] [amount] 여기서 [user]는 보낼 사용자이고 [amount]는 보낼 토큰의 양입니다. rl.on('line') 이전에 정의한 이벤트). 이는

var transactor = steemTransact(client, steem, 'first_steem_token_'); // ADD YOUR PREFIX HERE rl.on('line', function(data) { var split = data.split(' '); if(split[0] === 'balance') { var user = split[1]; var balance = state.balances[user]; if(balance === undefined) { balance = 0; } console.log(user, 'has', balance, 'tokens') } else if(split[0] === 'send') { console.log('Sending tokens...') var to = split[1]; var amount = parseInt(split[2]); transactor.json(username, key, 'send', { to: to, amount: amount }, function(err, result) { if(err) { console.error(err); } }) } else { console.log("Invalid command."); } });

그리고 지금까지의 스크립트는 다음과 같습니다.

var steem = require('dsteem');
var steemState = require('steem-state');
var steemTransact = require('steem-transact');
var readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout
}); var state = { balances: { shredz7: 990, ausbitbank: 10 }
} var username = 'your-username-here';
var key = 'your-private-posting-key-here'; var client = new steem.Client('https://api.steemit.com'); function startApp(dynamicGlobalProperties) { var processor = steemState(client, steem, dynamicGlobalProperties.head_block_number, 10, 'first_steem_token_'); processor.on('send', function(json, from) { if(json.to && typeof json.to === 'string' && typeof json.amount === 'number' && (json.amount | 0) === json.amount && json.amount >= 0 && state.balances[from] && state.balances[from] >= json.amount) { console.log('Send occurred from', from, 'to', json.to, 'of', json.amount, 'tokens.') if(state.balances[json.to] === undefined) { state.balances[json.to] = 0; } state.balances[json.to] += json.amount; state.balances[from] -= json.amount; } else { console.log('Invalid send operation from', from) } }) processor.start(); var transactor = steemTransact(client, steem, 'first_steem_token_'); // ADD YOUR PREFIX HERE rl.on('line', function(data) { var split = data.split(' '); if(split[0] === 'balance') { var user = split[1]; var balance = state.balances[user]; if(balance === undefined) { balance = 0; } console.log(user, 'has', balance, 'tokens') } else if(split[0] === 'send') { console.log('Sending tokens...') var to = split[1]; var amount = parseInt(split[2]); transactor.json(username, key, 'send', { to: to, amount: amount }, function(err, result) { if(err) { console.error(err); } }) } else { console.log("Invalid command."); } });
}
client.database.getDynamicGlobalProperties().then(startApp);

이것을 실행하면 Steem 블록체인을 사용하여 토큰을 보낼 수 있습니다(인내심을 가지십시오. 몇 초 정도 걸릴 수 있습니다). 축하해요! Steem 블록체인에 토큰을 성공적으로 생성했습니다!

하지만 우리 토큰에는 몇 가지 문제가 있으며 이를 설명하는 가장 좋은 방법은 다이어그램을 사용하는 것이라고 생각합니다.


이 다이어그램은 처음에는 혼란스러워 보이므로 여기에 설명이 있습니다. 이는 우리 코드와 유사한 것을 실행하는 여러 사용자와 시간 경과에 따른 상태를 보여주는 차트입니다(선이 내려갈수록 시간이 늘어납니다). 각각의 밝은 주황색/빨간색/노란색 상자는 사용자가 로그온할 때 표시됩니다(Alice, Bob 또는 Carl). 줄을 내려다보면 Bob과 Alice가 모두 녹색 상자에서 거래를 생성한 것을 볼 수 있습니다. 긴 선의 왼쪽에는 시간에 따른 각 사용자의 상태가 표시됩니다. Bob과 Alice의 상태를 살펴보면 그래프의 전체 기간 동안 항상 동일합니다(합의에 따라). 그러나 Carl의 상태를 살펴보면 Alice 및 Bob의 상태와 동일하지 않습니다.

Carl은 나중에 로그온했기 때문에 Alice가 생성한 첫 번째 트랜잭션(Bob에게 50개의 토큰을 보냈음)을 놓쳤습니다. 그 때문에 Bob과 Alice는 모두 상태에 동의하지만 Carl은 동의하지 않습니다. 그의 잔액을 보면 Alice와 Bob 사이의 거래가 전혀 발생하지 않았음을 알 수 있기 때문입니다.

이 문제를 해결하려면 Carl이 Alice와 Bob이 생성한 트랜잭션에 대해 알고 있는지 확인해야 합니다. 블록체인의 작동 방식과 유사하게 Carl은 실시간으로 작업하기 전에 이전의 모든 트랜잭션을 읽어야 단일 트랜잭션을 놓치지 않았는지 알 수 있습니다.

우리 DApp에는 genesisBlock: DApp이 존재했던 첫 번째 블록; 이전에 DApp의 접두사를 사용한 거래는 계산되지 않습니다. 새로운 사용자가 로그온할 때마다 해당 사용자가 로그온한 이후의 모든 작업을 처리합니다. genesisBlock 누락된 거래가 없는지 확인합니다(이는 블록체인 노드가 아무 것도 놓치지 않도록 제네시스 블록인 블록 0부터 모든 블록을 처리하는 방식과 유사합니다).

구현 genesisBlock 먼저 원하는 블록이 무엇이든 선언하겠습니다(매우 최근인지 확인하세요. 다음을 사용할 수 있습니다). 스팀블록탐색기 마지막 몇 블록의 번호가 무엇인지 확인하려면 최근 블록을 사용하지 않으면 이후의 모든 블록을 처리하는 데 매우 오랜 시간이 걸릴 수 있습니다. Steem 블록체인은 오랫동안 실행되어 왔습니다.) 그런 다음 우리는 client.database.getDynamicGlobalProperties 호출하고 블록 프로세서의 시작 블록을 다음과 같이 설정합니다. genesisBlock. 변경 후의 스크립트는 다음과 같습니다.

var steem = require('dsteem');
var steemState = require('steem-state');
var steemTransact = require('steem-transact');
var readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout
}); var genesisBlock = 28456664; // PUT A RECENT BLOCK HERE
var state = { balances: { shredz7: 990, ausbitbank: 10 }
} var username = 'your-username-here';
var key = 'your-private-posting-key-here'; var client = new steem.Client('https://api.steemit.com'); function startApp() { var processor = steemState(client, steem, genesisBlock, 10, 'first_steem_token_'); processor.on('send', function(json, from) { if(json.to && typeof json.to === 'string' && typeof json.amount === 'number' && (json.amount | 0) === json.amount && json.amount >= 0 && state.balances[from] && state.balances[from] >= json.amount) { console.log('Send occurred from', from, 'to', json.to, 'of', json.amount, 'tokens.') if(state.balances[json.to] === undefined) { state.balances[json.to] = 0; } state.balances[json.to] += json.amount; state.balances[from] -= json.amount; } else { console.log('Invalid send operation from', from) } }); processor.start(); var transactor = steemTransact(client, steem, 'first_steem_token_'); // ADD YOUR PREFIX HERE rl.on('line', function(data) { var split = data.split(' '); if(split[0] === 'balance') { var user = split[1]; var balance = state.balances[user]; if(balance === undefined) { balance = 0; } console.log(user, 'has', balance, 'tokens') } else if(split[0] === 'send') { console.log('Sending tokens...') var to = split[1]; var amount = parseInt(split[2]); transactor.json(username, key, 'send', { to: to, amount: amount }, function(err, result) { if(err) { console.error(err); } }) } else { console.log("Invalid command."); } });
}
startApp();

코드를 실행하면 실제로 아무것도 바뀌지 않습니다. 프로세서가 모든 작업을 읽기 위해 뒤에서 열심히 작업하더라도 정확히 동일하게 보일 것입니다. genesisBlock. 사용자에게 블록 계산 진행 상황을 알려주는 몇 가지 알림을 추가해 보겠습니다. 이 내용은 이전에 추가될 예정입니다. processor.start() 하지만 후 procesor.on('send'). 우리는 세 가지 새로운 API 함수를 사용할 것입니다: onBlock, isStreamingonStreamingStart.

onBlock: 블록 번호와 블록 데이터를 사용하여 블록마다 콜백을 호출합니다.
isStreaming: 프로세서가 실시간으로 블록을 가져오는 경우(블록체인을 따라잡는 경우) true를 반환합니다.
onStreamingStart: 프로세서가 실시간으로 블록을 받기 시작하면 콜백을 호출합니다(블록체인을 따라잡습니다).

실시간이 아닌 동안에는 100블록마다 진행 상황을 인쇄한 다음 "실시간"으로 인쇄하겠습니다. 우리가 블록체인을 따라잡고 블록을 실시간으로 스트리밍하고 있을 때 말이죠.

 processor.onBlock(function(num, block) { if(num % 100 === 0 && !processor.isStreaming()) { client.database.getDynamicGlobalProperties().then(function(result) { console.log('At block', num, 'with', result.head_block_number-num, 'left until real-time.') }); } }); processor.onStreamingStart(function() { console.log("At real time.") });

이제 전체 코드는 다음과 같습니다.

var steem = require('dsteem');
var steemState = require('steem-state');
var steemTransact = require('steem-transact');
var readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout
}); var genesisBlock = 28456664; // PUT A RECENT BLOCK HERE
var state = { balances: { shredz7: 990, ausbitbank: 10 }
} var username = 'your-username-here';
var key = 'your-private-posting-key-here'; var client = new steem.Client('https://api.steemit.com'); function startApp() { var processor = steemState(client, steem, genesisBlock, 10, 'first_steem_token_'); processor.on('send', function(json, from) { if(json.to && typeof json.to === 'string' && typeof json.amount === 'number' && (json.amount | 0) === json.amount && json.amount >= 0 && state.balances[from] && state.balances[from] >= json.amount) { console.log('Send occurred from', from, 'to', json.to, 'of', json.amount, 'tokens.') if(state.balances[json.to] === undefined) { state.balances[json.to] = 0; } state.balances[json.to] += json.amount; state.balances[from] -= json.amount; } else { console.log('Invalid send operation from', from) } }); processor.onBlock(function(num, block) { if(num % 100 === 0 && !processor.isStreaming()) { client.database.getDynamicGlobalProperties().then(function(result) { console.log('At block', num, 'with', result.head_block_number-num, 'left until real-time.') }); } }); processor.onStreamingStart(function() { console.log("At real time.") }); processor.start(); var transactor = steemTransact(client, steem, 'first_steem_token_'); // ADD YOUR PREFIX HERE rl.on('line', function(data) { var split = data.split(' '); if(split[0] === 'balance') { var user = split[1]; var balance = state.balances[user]; if(balance === undefined) { balance = 0; } console.log(user, 'has', balance, 'tokens') } else if(split[0] === 'send') { console.log('Sending tokens...') var to = split[1]; var amount = parseInt(split[2]); transactor.json(username, key, 'send', { to: to, amount: amount }, function(err, result) { if(err) { console.error(err); } }) } else { console.log("Invalid command."); } });
}
startApp();

아휴! 이제 끝났습니다! 이 코드를 실행하면 지난 블록을 읽는 동안 노드의 진행 상황을 보여주는 출력을 얻을 수 있습니다. 보시다시피 Steem RPC 서버와 우리 노드가 각 블록에 대해 서로 대화하는 데 꽤 오랜 시간이 걸립니다. 더 나은 효율성은 제가 업데이트하고 싶은 큰 일이 될 것입니다 steem-state 하지만 지금은 효율성이 충분합니다. 프로세서를 생성할 때 블록 컴퓨팅 속도를 10밀리초로 설정한 방법에 주목하세요. 이는 노드가 Steem RPC 서버에 요청을 보내는 사이에 10밀리초 동안 대기한다는 의미입니다. 일반적으로 실행하게 될 이러한 노드는 긴 시작 시간을 피하기 위해 매일 하루 종일 실행되어야 합니다(또한 향후 프로젝트를 위해 이 프로젝트에 제안하는 두 번째 추가 기능을 사용하십시오).

노드가 실행되면 다른 계정과 거래할 수 있어야 하며 다른 계정이 귀하와 거래하도록 할 수도 있습니다! Steem 블록체인에 토큰을 구축한 것을 축하합니다!

이 프로젝트에 추가할 몇 가지 사항:

  1. CLI 내에서 사용자에게 사용자 이름과 키를 물어보세요. 로그인하기 위해 코드를 수정해야 하는 것은 좋은 사용자 경험이 아닙니다.
  2. 종료하는 동안 상태를 저장합니다. 다음과 같은 일종의 CLI 입력을 추가하세요. exit 이는 프로세서를 호출합니다. stop 기능(참조 선적 서류 비치), 프로세서가 중지되면 마지막 블록 번호와 함께 상태를 파일에 저장하고 호출합니다. process.exit. 그런 다음 프로그램이 백업을 시작할 때 해당 상태 파일을 로드하고 파일에 포함된 상태를 사용하여 해당 파일에 포함된 마지막 블록 번호부터 시작합니다. 따라서 사용자가 노드를 다시 로드할 때 전체 기록을 살펴볼 필요가 없으며 이전에 종료했을 때 중지했던 위치로 돌아가기만 하면 됩니다. 이 작업은 다음에서도 수행됩니다. 두 번째 튜토리얼.

읽기 소프트 컨센서스 DApp을 구축하는 동안 고려 사항에 대한 안내, Steem 블록체인에 차세대 킬러 DApp을 구축해보세요!!!

2 튜토리얼 여기에서 지금 확인해 보세요. 최신 기능에 대한 정보, 상태를 파일에 저장하고 토큰을 기반으로 SMT를 생성하는 정보가 포함되어 있습니다.

작업 완료 증명

https://gist.github.com/nicholas-2/5f8309f191a1c61e13fc9e876f8cada5

궁금하신 점은 본 포스팅에 댓글을 남겨주시거나, 제 이메일로 연락주세요. [이메일 보호]

출처: https://steemit.com/utopian-io/@shredz7/the-first-token-on-the-steem-blockchain

spot_img

최신 인텔리전스

spot_img