mirror of
https://github.com/number571/blockchain.git
synced 2026-09-13 18:45:45 +05:00
update again
This commit is contained in:
parent
e9b11c1972
commit
06bfdfeea3
@ -1,6 +1,8 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"time"
|
||||
"errors"
|
||||
"bytes"
|
||||
"crypto/rsa"
|
||||
"math/big"
|
||||
@ -16,6 +18,178 @@ func NewBlock(miner string, prevHash []byte) *Block {
|
||||
}
|
||||
}
|
||||
|
||||
func (block *Block) Accept(chain *BlockChain, user *User, ch chan bool) error {
|
||||
if !block.transactionsIsValid(chain) {
|
||||
return errors.New("transactions is not valid")
|
||||
}
|
||||
block.AddTransaction(chain, &Transaction{
|
||||
RandBytes: GenerateRandomBytes(RAND_BYTES),
|
||||
Sender: STORAGE_CHAIN,
|
||||
Receiver: user.Address(),
|
||||
Value: STORAGE_REWARD,
|
||||
})
|
||||
block.TimeStamp = time.Now().Format(time.RFC3339)
|
||||
block.CurrHash = block.hash()
|
||||
block.Signature = block.sign(user.Private())
|
||||
block.Nonce = block.proof(ch)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (block *Block) AddTransaction(chain *BlockChain, tx *Transaction) error {
|
||||
if tx.Value == 0 {
|
||||
return errors.New("tx value = 0")
|
||||
}
|
||||
if len(block.Transactions) == TXS_LIMIT && tx.Sender != STORAGE_CHAIN {
|
||||
return errors.New("len tx = limit")
|
||||
}
|
||||
var balanceInChain uint64
|
||||
balanceInTX := tx.Value + tx.ToStorage
|
||||
if value, ok := block.Mapping[tx.Sender]; ok {
|
||||
balanceInChain = value
|
||||
} else {
|
||||
balanceInChain = chain.Balance(tx.Sender)
|
||||
}
|
||||
if tx.Value > START_PERCENT && tx.ToStorage != STORAGE_REWARD {
|
||||
return errors.New("storage reward pass")
|
||||
}
|
||||
if balanceInTX > balanceInChain {
|
||||
return errors.New("insufficient funds")
|
||||
}
|
||||
block.Mapping[tx.Sender] = balanceInChain - balanceInTX
|
||||
block.addBalance(chain, tx.Receiver, tx.Value)
|
||||
block.addBalance(chain, STORAGE_CHAIN, tx.ToStorage)
|
||||
block.Transactions = append(block.Transactions, *tx)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (block *Block) IsValid(chain *BlockChain) bool {
|
||||
switch {
|
||||
case block == nil:
|
||||
return false
|
||||
case block.Difficulty != DIFFICULTY:
|
||||
return false
|
||||
case !block.hashIsValid(chain, chain.Size()):
|
||||
return false
|
||||
case !block.signIsValid():
|
||||
return false
|
||||
case !block.proofIsValid():
|
||||
return false
|
||||
case !block.mappingIsValid():
|
||||
return false
|
||||
case !block.timeIsValid(chain, chain.Size()):
|
||||
return false
|
||||
case !block.transactionsIsValid(chain):
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (block *Block) timeIsValid(chain *BlockChain, index uint64) bool {
|
||||
btime, err := time.Parse(time.RFC3339, block.TimeStamp)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
diff := time.Now().Sub(btime)
|
||||
if diff < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var sblock string
|
||||
row := chain.DB.QueryRow("SELECT Block FROM BlockChain WHERE Hash=$1",
|
||||
Base64Encode(block.PrevHash))
|
||||
row.Scan(&sblock)
|
||||
|
||||
lblock := DeserializeBlock(sblock)
|
||||
if lblock == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
ltime, err := time.Parse(time.RFC3339, lblock.TimeStamp)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
result := btime.Sub(ltime)
|
||||
return result > 0
|
||||
}
|
||||
|
||||
func (block *Block) transactionsIsValid(chain *BlockChain) bool {
|
||||
lentxs := len(block.Transactions)
|
||||
plusStorage := 0
|
||||
for i := 0; i < lentxs; i++ {
|
||||
if block.Transactions[i].Sender == STORAGE_CHAIN {
|
||||
plusStorage = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if lentxs == 0 || lentxs > TXS_LIMIT+plusStorage {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < lentxs-1; i++ {
|
||||
for j := i + 1; j < lentxs; j++ {
|
||||
// rand bytes not be equal
|
||||
if bytes.Equal(block.Transactions[i].RandBytes, block.Transactions[j].RandBytes) {
|
||||
return false
|
||||
}
|
||||
// storage tx only one
|
||||
if block.Transactions[i].Sender == STORAGE_CHAIN &&
|
||||
block.Transactions[j].Sender == STORAGE_CHAIN {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := 0; i < lentxs; i++ {
|
||||
tx := block.Transactions[i]
|
||||
// storage tx has no hash and signature
|
||||
if tx.Sender == STORAGE_CHAIN {
|
||||
if tx.Receiver != block.Miner || tx.Value != STORAGE_REWARD {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if !tx.hashIsValid() {
|
||||
return false
|
||||
}
|
||||
if !tx.signIsValid() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if !block.balanceIsValid(chain, tx.Sender) {
|
||||
return false
|
||||
}
|
||||
if !block.balanceIsValid(chain, tx.Receiver) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (block *Block) balanceIsValid(chain *BlockChain, address string) bool {
|
||||
if _, ok := block.Mapping[address]; !ok {
|
||||
return false
|
||||
}
|
||||
lentxs := len(block.Transactions)
|
||||
balanceInChain := chain.Balance(address)
|
||||
balanceSubBlock := uint64(0)
|
||||
balanceAddBlock := uint64(0)
|
||||
for j := 0; j < lentxs; j++ {
|
||||
tx := block.Transactions[j]
|
||||
if tx.Sender == address {
|
||||
balanceSubBlock += tx.Value + tx.ToStorage
|
||||
}
|
||||
if tx.Receiver == address {
|
||||
balanceAddBlock += tx.Value
|
||||
}
|
||||
if STORAGE_CHAIN == address {
|
||||
balanceAddBlock += tx.ToStorage
|
||||
}
|
||||
}
|
||||
if (balanceInChain + balanceAddBlock - balanceSubBlock) != block.Mapping[address] {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (block *Block) hash() []byte {
|
||||
var tempHash []byte
|
||||
for _, tx := range block.Transactions {
|
||||
@ -62,8 +236,15 @@ func (block *Block) proof(ch chan bool) uint64 {
|
||||
return ProofOfWork(block.CurrHash, block.Difficulty, ch)
|
||||
}
|
||||
|
||||
func (block *Block) hashIsValid() bool {
|
||||
return bytes.Equal(block.hash(), block.CurrHash)
|
||||
func (block *Block) hashIsValid(chain *BlockChain, index uint64) bool {
|
||||
if !bytes.Equal(block.hash(), block.CurrHash) {
|
||||
return false
|
||||
}
|
||||
var id uint64
|
||||
row := chain.DB.QueryRow("SELECT Id FROM BlockChain WHERE Hash=$1",
|
||||
Base64Encode(block.PrevHash))
|
||||
row.Scan(&id)
|
||||
return id == index
|
||||
}
|
||||
|
||||
func (block *Block) signIsValid() bool {
|
||||
|
||||
@ -49,30 +49,6 @@ func LoadChain(filename string) *BlockChain {
|
||||
return chain
|
||||
}
|
||||
|
||||
func (chain *BlockChain) BlockIsValid(block *Block) bool {
|
||||
switch {
|
||||
case block == nil:
|
||||
return false
|
||||
case block.Difficulty != DIFFICULTY:
|
||||
return false
|
||||
case !block.hashIsValid():
|
||||
return false
|
||||
case !chain.hashIsValid(block, chain.Size()):
|
||||
return false
|
||||
case !block.signIsValid():
|
||||
return false
|
||||
case !block.proofIsValid():
|
||||
return false
|
||||
case !block.mappingIsValid():
|
||||
return false
|
||||
case !chain.timeIsValid(block, chain.Size()):
|
||||
return false
|
||||
case !chain.transactionsIsValid(block):
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (chain *BlockChain) Size() uint64 {
|
||||
var index uint64
|
||||
row := chain.DB.QueryRow("SELECT Id FROM BlockChain ORDER BY Id DESC")
|
||||
@ -111,16 +87,10 @@ func (chain *BlockChain) PrintChain() error {
|
||||
fmt.Printf("[%d][SUCCESS] difficulty is valid\n", index)
|
||||
}
|
||||
|
||||
if !block.hashIsValid() {
|
||||
fmt.Printf("[%d][FAILED] block hash is not valid\n", index)
|
||||
if !block.hashIsValid(chain, index-1) {
|
||||
fmt.Printf("[%d][FAILED] hash is not valid\n", index)
|
||||
} else {
|
||||
fmt.Printf("[%d][SUCCESS] block hash is valid\n", index)
|
||||
}
|
||||
|
||||
if !chain.hashIsValid(block, index-1) {
|
||||
fmt.Printf("[%d][FAILED] chain hash is not valid\n", index)
|
||||
} else {
|
||||
fmt.Printf("[%d][SUCCESS] chain hash is valid\n", index)
|
||||
fmt.Printf("[%d][SUCCESS] hash is valid\n", index)
|
||||
}
|
||||
|
||||
if !block.signIsValid() {
|
||||
@ -141,7 +111,7 @@ func (chain *BlockChain) PrintChain() error {
|
||||
fmt.Printf("[%d][SUCCESS] mapping is valid\n", index)
|
||||
}
|
||||
|
||||
if !chain.timeIsValid(block, index-1) {
|
||||
if !block.timeIsValid(chain, index-1) {
|
||||
fmt.Printf("[%d][FAILED] time is not valid\n", index)
|
||||
} else {
|
||||
fmt.Printf("[%d][SUCCESS] time is valid\n", index)
|
||||
@ -149,7 +119,7 @@ func (chain *BlockChain) PrintChain() error {
|
||||
|
||||
size = chain.index
|
||||
chain.index = index - 1
|
||||
if !chain.transactionsIsValid(block) {
|
||||
if !block.transactionsIsValid(chain) {
|
||||
fmt.Printf("[%d][FAILED] transactions is not valid\n", index)
|
||||
} else {
|
||||
fmt.Printf("[%d][SUCCESS] transactions is valid\n", index)
|
||||
@ -168,7 +138,8 @@ func (chain *BlockChain) Balance(address string) uint64 {
|
||||
block *Block
|
||||
balance uint64
|
||||
)
|
||||
rows, err := chain.DB.Query("SELECT Block FROM BlockChain WHERE Id <= $1 ORDER BY Id DESC", chain.index)
|
||||
rows, err := chain.DB.Query("SELECT Block FROM BlockChain WHERE Id <= $1 ORDER BY Id DESC",
|
||||
chain.index)
|
||||
if err != nil {
|
||||
return balance
|
||||
}
|
||||
@ -191,23 +162,6 @@ func (chain *BlockChain) LastHash() []byte {
|
||||
return Base64Decode(hash)
|
||||
}
|
||||
|
||||
func (chain *BlockChain) AcceptBlock(user *User, block *Block, ch chan bool) *Block {
|
||||
if !chain.transactionsIsValid(block) {
|
||||
return nil
|
||||
}
|
||||
block.AddTransaction(chain, &Transaction{
|
||||
RandBytes: GenerateRandomBytes(RAND_BYTES),
|
||||
Sender: STORAGE_CHAIN,
|
||||
Receiver: user.Address(),
|
||||
Value: STORAGE_REWARD,
|
||||
})
|
||||
block.TimeStamp = time.Now().Format(time.RFC3339)
|
||||
block.CurrHash = block.hash()
|
||||
block.Signature = block.sign(user.Private())
|
||||
block.Nonce = block.proof(ch)
|
||||
return block
|
||||
}
|
||||
|
||||
func (chain *BlockChain) AddBlock(block *Block) {
|
||||
chain.index += 1
|
||||
chain.DB.Exec("INSERT INTO BlockChain (Hash, Block) VALUES ($1, $2)",
|
||||
@ -215,114 +169,3 @@ func (chain *BlockChain) AddBlock(block *Block) {
|
||||
SerializeBlock(block),
|
||||
)
|
||||
}
|
||||
|
||||
func (chain *BlockChain) timeIsValid(block *Block, index uint64) bool {
|
||||
btime, err := time.Parse(time.RFC3339, block.TimeStamp)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
diff := time.Now().Sub(btime)
|
||||
if diff < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var sblock string
|
||||
row := chain.DB.QueryRow("SELECT Block FROM BlockChain WHERE Hash=$1", Base64Encode(block.PrevHash))
|
||||
row.Scan(&sblock)
|
||||
|
||||
lblock := DeserializeBlock(sblock)
|
||||
if lblock == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
ltime, err := time.Parse(time.RFC3339, lblock.TimeStamp)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
result := btime.Sub(ltime)
|
||||
return result > 0
|
||||
}
|
||||
|
||||
func (chain *BlockChain) hashIsValid(block *Block, index uint64) bool {
|
||||
var id uint64
|
||||
row := chain.DB.QueryRow("SELECT Id FROM BlockChain WHERE Hash=$1", Base64Encode(block.PrevHash))
|
||||
row.Scan(&id)
|
||||
return id == index
|
||||
}
|
||||
|
||||
func (chain *BlockChain) transactionsIsValid(block *Block) bool {
|
||||
lentxs := len(block.Transactions)
|
||||
plusStorage := 0
|
||||
for i := 0; i < lentxs; i++ {
|
||||
if block.Transactions[i].Sender == STORAGE_CHAIN {
|
||||
plusStorage = 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if lentxs == 0 || lentxs > TXS_LIMIT+plusStorage {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < lentxs-1; i++ {
|
||||
for j := i + 1; j < lentxs; j++ {
|
||||
// rand bytes not be equal
|
||||
if bytes.Equal(block.Transactions[i].RandBytes, block.Transactions[j].RandBytes) {
|
||||
return false
|
||||
}
|
||||
// storage tx only one
|
||||
if block.Transactions[i].Sender == STORAGE_CHAIN && block.Transactions[j].Sender == STORAGE_CHAIN {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := 0; i < lentxs; i++ {
|
||||
tx := block.Transactions[i]
|
||||
// storage tx has no hash and signature
|
||||
if tx.Sender == STORAGE_CHAIN {
|
||||
if tx.Receiver != block.Miner || tx.Value != STORAGE_REWARD {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if !tx.hashIsValid() {
|
||||
return false
|
||||
}
|
||||
if !tx.signIsValid() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if !chain.balanceIsValid(block, tx.Sender) {
|
||||
return false
|
||||
}
|
||||
if !chain.balanceIsValid(block, tx.Receiver) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (chain *BlockChain) balanceIsValid(block *Block, address string) bool {
|
||||
lentxs := len(block.Transactions)
|
||||
balanceInChain := chain.Balance(address)
|
||||
balanceSubBlock := uint64(0)
|
||||
balanceAddBlock := uint64(0)
|
||||
for j := 0; j < lentxs; j++ {
|
||||
tx := block.Transactions[j]
|
||||
if tx.Sender == address {
|
||||
balanceSubBlock += tx.Value + tx.ToStorage
|
||||
}
|
||||
if tx.Receiver == address {
|
||||
balanceAddBlock += tx.Value
|
||||
}
|
||||
if STORAGE_CHAIN == address {
|
||||
balanceAddBlock += tx.ToStorage
|
||||
}
|
||||
}
|
||||
if _, ok := block.Mapping[address]; !ok {
|
||||
return false
|
||||
}
|
||||
if (balanceInChain + balanceAddBlock - balanceSubBlock) != block.Mapping[address] {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -15,7 +15,6 @@ import (
|
||||
mrand "math/rand"
|
||||
)
|
||||
|
||||
// Create private key by size bits.
|
||||
func GeneratePrivate(bits uint16) *rsa.PrivateKey {
|
||||
priv, err := rsa.GenerateKey(rand.Reader, int(bits))
|
||||
if err != nil {
|
||||
@ -24,7 +23,6 @@ func GeneratePrivate(bits uint16) *rsa.PrivateKey {
|
||||
return priv
|
||||
}
|
||||
|
||||
// Generate bytes in range [0:256).
|
||||
func GenerateRandomBytes(max uint) []byte {
|
||||
var slice []byte = make([]byte, max)
|
||||
_, err := rand.Read(slice)
|
||||
@ -34,13 +32,11 @@ func GenerateRandomBytes(max uint) []byte {
|
||||
return slice
|
||||
}
|
||||
|
||||
// SHA256(bytes).
|
||||
func HashSum(data []byte) []byte {
|
||||
hash := sha256.Sum256(data)
|
||||
return hash[:]
|
||||
}
|
||||
|
||||
// Sign data by private key.
|
||||
func Sign(priv *rsa.PrivateKey, data []byte) []byte {
|
||||
signature, err := rsa.SignPSS(rand.Reader, priv, crypto.SHA256, data, nil)
|
||||
if err != nil {
|
||||
@ -49,12 +45,10 @@ func Sign(priv *rsa.PrivateKey, data []byte) []byte {
|
||||
return signature
|
||||
}
|
||||
|
||||
// Verify data and signature by public key.
|
||||
func Verify(pub *rsa.PublicKey, data, sign []byte) error {
|
||||
return rsa.VerifyPSS(pub, crypto.SHA256, data, sign, nil)
|
||||
}
|
||||
|
||||
// POW for check hash package by Nonce.
|
||||
func ProofOfWork(blockHash []byte, difficulty uint8, ch chan bool) uint64 {
|
||||
var (
|
||||
Target = big.NewInt(1)
|
||||
@ -94,12 +88,10 @@ func ProofOfWork(blockHash []byte, difficulty uint8, ch chan bool) uint64 {
|
||||
return nonce
|
||||
}
|
||||
|
||||
// base64.StdEncoding.EncodeToString
|
||||
func Base64Encode(data []byte) string {
|
||||
return base64.StdEncoding.EncodeToString(data)
|
||||
}
|
||||
|
||||
// base64.StdEncoding.DecodeString
|
||||
func Base64Decode(data string) []byte {
|
||||
result, err := base64.StdEncoding.DecodeString(data)
|
||||
if err != nil {
|
||||
@ -108,7 +100,6 @@ func Base64Decode(data string) []byte {
|
||||
return result
|
||||
}
|
||||
|
||||
// Translate uint64 to slice of bytes.
|
||||
func ToBytes(num uint64) []byte {
|
||||
var data = new(bytes.Buffer)
|
||||
err := binary.Write(data, binary.BigEndian, num)
|
||||
@ -118,12 +109,10 @@ func ToBytes(num uint64) []byte {
|
||||
return data.Bytes()
|
||||
}
|
||||
|
||||
// Translate public key as *rsa.PublicKey to string.
|
||||
func StringPublic(pub *rsa.PublicKey) string {
|
||||
return Base64Encode(x509.MarshalPKCS1PublicKey(pub))
|
||||
}
|
||||
|
||||
// Translate public key as string to *rsa.PublicKey.
|
||||
func ParsePublic(pubData string) *rsa.PublicKey {
|
||||
pub, err := x509.ParsePKCS1PublicKey(Base64Decode(pubData))
|
||||
if err != nil {
|
||||
@ -132,12 +121,10 @@ func ParsePublic(pubData string) *rsa.PublicKey {
|
||||
return pub
|
||||
}
|
||||
|
||||
// Translate public key as *rsa.PublicKey to string.
|
||||
func StringPrivate(priv *rsa.PrivateKey) string {
|
||||
return Base64Encode(x509.MarshalPKCS1PrivateKey(priv))
|
||||
}
|
||||
|
||||
// Translate public key as string to *rsa.PublicKey.
|
||||
func ParsePrivate(privData string) *rsa.PrivateKey {
|
||||
pub, err := x509.ParsePKCS1PrivateKey(Base64Decode(privData))
|
||||
if err != nil {
|
||||
|
||||
@ -21,7 +21,6 @@ CREATE TABLE BlockChain (
|
||||
)
|
||||
|
||||
const (
|
||||
// DEBUG = false
|
||||
DEBUG = true
|
||||
KEY_SIZE = 512
|
||||
STORAGE_CHAIN = "STORAGE-CHAIN"
|
||||
@ -29,8 +28,8 @@ const (
|
||||
STORAGE_REWARD = 1
|
||||
GENESIS_BLOCK = "GENESIS-BLOCK"
|
||||
GENESIS_REWARD = 100
|
||||
DIFFICULTY = 20 // 15
|
||||
TXS_LIMIT = 2 // 6
|
||||
DIFFICULTY = 20
|
||||
TXS_LIMIT = 2
|
||||
START_PERCENT = 10
|
||||
RAND_BYTES = 32
|
||||
)
|
||||
@ -47,16 +46,16 @@ type Block struct {
|
||||
PrevHash []byte
|
||||
Transactions []Transaction
|
||||
Mapping map[string]uint64
|
||||
Miner string // Hashname
|
||||
Signature []byte // Miner sign
|
||||
Miner string
|
||||
Signature []byte
|
||||
TimeStamp string
|
||||
}
|
||||
|
||||
type Transaction struct {
|
||||
RandBytes []byte
|
||||
PrevBlock []byte
|
||||
Sender string // Hashname
|
||||
Receiver string // Hashname
|
||||
Sender string
|
||||
Receiver string
|
||||
Value uint64
|
||||
ToStorage uint64
|
||||
CurrHash []byte
|
||||
|
||||
@ -3,7 +3,6 @@ package blockchain
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rsa"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func NewTransaction(user *User, lasthash []byte, to string, value uint64) *Transaction {
|
||||
@ -22,32 +21,12 @@ func NewTransaction(user *User, lasthash []byte, to string, value uint64) *Trans
|
||||
return tx
|
||||
}
|
||||
|
||||
func (block *Block) AddTransaction(chain *BlockChain, tx *Transaction) error {
|
||||
if len(block.Transactions) == TXS_LIMIT && tx.Sender != STORAGE_CHAIN {
|
||||
return errors.New("len tx = limit")
|
||||
}
|
||||
balanceInChain := chain.Balance(tx.Sender)
|
||||
balanceInBlock := tx.Value + tx.ToStorage
|
||||
if value, ok := block.Mapping[tx.Sender]; ok {
|
||||
balanceInChain = value
|
||||
}
|
||||
if tx.Value > START_PERCENT && tx.ToStorage != STORAGE_REWARD {
|
||||
return errors.New("storage reward pass")
|
||||
}
|
||||
if balanceInBlock > balanceInChain {
|
||||
return errors.New("insufficient funds")
|
||||
}
|
||||
block.Mapping[tx.Sender] = balanceInChain - balanceInBlock
|
||||
chain.addBalance(block, tx.Receiver, tx.Value)
|
||||
chain.addBalance(block, STORAGE_CHAIN, tx.ToStorage)
|
||||
block.Transactions = append(block.Transactions, *tx)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (chain *BlockChain) addBalance(block *Block, receiver string, value uint64) {
|
||||
balanceInChain := chain.Balance(receiver)
|
||||
func (block *Block) addBalance(chain *BlockChain, receiver string, value uint64) {
|
||||
var balanceInChain uint64
|
||||
if v, ok := block.Mapping[receiver]; ok {
|
||||
balanceInChain = v
|
||||
} else {
|
||||
balanceInChain = chain.Balance(receiver)
|
||||
}
|
||||
block.Mapping[receiver] = balanceInChain + value
|
||||
}
|
||||
|
||||
18
client.go
18
client.go
@ -104,6 +104,8 @@ func handleClient() {
|
||||
case "balance":
|
||||
chainBalance(splited[1:])
|
||||
}
|
||||
default:
|
||||
fmt.Println("command undefined\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,7 +113,7 @@ func handleClient() {
|
||||
func chainPrint() {
|
||||
for i := 0; ; i++ {
|
||||
res := nt.Send(Addresses[0], &nt.Package{
|
||||
Option: GET_CHAIN,
|
||||
Option: GET_BLOCK,
|
||||
Data: fmt.Sprintf("%d", i),
|
||||
})
|
||||
if res.Data == "" {
|
||||
@ -134,14 +136,14 @@ func chainTX(splited []string) {
|
||||
}
|
||||
for _, addr := range Addresses {
|
||||
res := nt.Send(addr, &nt.Package{
|
||||
Option: GET_LASTHASH,
|
||||
Option: GET_LHASH,
|
||||
})
|
||||
if res == nil {
|
||||
continue
|
||||
}
|
||||
tx := bc.NewTransaction(User, bc.Base64Decode(res.Data), splited[1], uint64(num))
|
||||
res = nt.Send(addr, &nt.Package{
|
||||
Option: ADD_TRANSACTION,
|
||||
Option: ADD_TRNSX,
|
||||
Data: bc.SerializeTX(tx),
|
||||
})
|
||||
if res == nil {
|
||||
@ -164,14 +166,10 @@ func chainBalance(splited []string) {
|
||||
printBalance(splited[1])
|
||||
}
|
||||
|
||||
func userBalance() {
|
||||
printBalance(User.Address())
|
||||
}
|
||||
|
||||
func printBalance(useraddr string) {
|
||||
for _, addr := range Addresses {
|
||||
res := nt.Send(addr, &nt.Package{
|
||||
Option: GET_BALANCE,
|
||||
Option: GET_BLNCE,
|
||||
Data: useraddr,
|
||||
})
|
||||
fmt.Printf("Balance (%s): %s coins\n", addr, res.Data)
|
||||
@ -187,6 +185,10 @@ func userPurse() {
|
||||
fmt.Println("Purse:", User.Purse(), "\n")
|
||||
}
|
||||
|
||||
func userBalance() {
|
||||
printBalance(User.Address())
|
||||
}
|
||||
|
||||
func inputString(begin string) string {
|
||||
fmt.Print(begin)
|
||||
msg, _ := bufio.NewReader(os.Stdin).ReadString('\n')
|
||||
|
||||
@ -50,7 +50,7 @@ func Send(address string, pack *Package) *Package {
|
||||
return readPackage(conn)
|
||||
}
|
||||
|
||||
func Handle(option string, conn Conn, pack *Package, handle func(*Package) string) bool {
|
||||
func Handle(option int, conn Conn, pack *Package, handle func(*Package) string) bool {
|
||||
if pack.Option != option {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ const (
|
||||
)
|
||||
|
||||
type Package struct {
|
||||
Option string
|
||||
Option int
|
||||
Data string
|
||||
}
|
||||
|
||||
9
node.go
9
node.go
@ -53,8 +53,10 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
if !(userNewExist || userLoadExist) || !(chainNewExist || chainLoadExist) || !serveExist || !addrExist {
|
||||
panic("failed: !(userNewExist || userLoadExist) || !(chainNewExist || chainLoadExist) || !serveExist || !addrExist")
|
||||
if !(userNewExist || userLoadExist) || !(chainNewExist || chainLoadExist) ||
|
||||
!serveExist || !addrExist {
|
||||
panic("failed: !(userNewExist || userLoadExist)"+
|
||||
"|| !(chainNewExist || chainLoadExist) || !serveExist || !addrExist")
|
||||
}
|
||||
|
||||
Serve = serveStr
|
||||
@ -111,9 +113,6 @@ func main() {
|
||||
}
|
||||
|
||||
func chainNew(filename string) *bc.BlockChain {
|
||||
if User == nil {
|
||||
return nil
|
||||
}
|
||||
err := bc.NewChain(filename, User.Address())
|
||||
if err != nil {
|
||||
return nil
|
||||
|
||||
47
serve.go
47
serve.go
@ -19,21 +19,19 @@ var (
|
||||
Serve string
|
||||
Chain *bc.BlockChain
|
||||
Block *bc.Block
|
||||
)
|
||||
|
||||
var (
|
||||
IsMining bool
|
||||
BreakMining = make(chan bool)
|
||||
)
|
||||
|
||||
func handleServer(conn nt.Conn, pack *nt.Package) {
|
||||
nt.Handle(GET_SIZE, conn, pack, getSize)
|
||||
nt.Handle(ADD_BLOCK, conn, pack, addBlock)
|
||||
nt.Handle(GET_CHAIN, conn, pack, getChain)
|
||||
nt.Handle(GET_LASTHASH, conn, pack, getLastHash)
|
||||
nt.Handle(GET_BALANCE, conn, pack, getBalance)
|
||||
nt.Handle(ADD_TRANSACTION, conn, pack, addTransaction)
|
||||
}
|
||||
|
||||
func getSize(pack *nt.Package) string {
|
||||
return fmt.Sprintf("%d", Chain.Size())
|
||||
nt.Handle(GET_BLOCK, conn, pack, getBlock)
|
||||
nt.Handle(GET_LHASH, conn, pack, getLastHash)
|
||||
nt.Handle(GET_BLNCE, conn, pack, getBalance)
|
||||
nt.Handle(ADD_TRNSX, conn, pack, addTransaction)
|
||||
}
|
||||
|
||||
func addBlock(pack *nt.Package) string {
|
||||
@ -41,8 +39,9 @@ func addBlock(pack *nt.Package) string {
|
||||
if len(splited) != 3 {
|
||||
return "fail"
|
||||
}
|
||||
|
||||
block := bc.DeserializeBlock(splited[2])
|
||||
if !Chain.BlockIsValid(block) {
|
||||
if !block.IsValid(Chain) {
|
||||
currSize := Chain.Size()
|
||||
num, err := strconv.Atoi(splited[1])
|
||||
if err != nil {
|
||||
@ -77,7 +76,7 @@ func compareChains(address string, num uint64) string {
|
||||
}()
|
||||
|
||||
res := nt.Send(address, &nt.Package{
|
||||
Option: GET_CHAIN,
|
||||
Option: GET_BLOCK,
|
||||
Data: fmt.Sprintf("%d", 0),
|
||||
})
|
||||
if res == nil {
|
||||
@ -107,7 +106,7 @@ func compareChains(address string, num uint64) string {
|
||||
|
||||
for i := uint64(1); i < num; i++ {
|
||||
res := nt.Send(address, &nt.Package{
|
||||
Option: GET_CHAIN,
|
||||
Option: GET_BLOCK,
|
||||
Data: fmt.Sprintf("%d", i),
|
||||
})
|
||||
if res == nil {
|
||||
@ -117,7 +116,7 @@ func compareChains(address string, num uint64) string {
|
||||
if block == nil {
|
||||
return "fail"
|
||||
}
|
||||
if !chain.BlockIsValid(block) {
|
||||
if !block.IsValid(chain) {
|
||||
return "fail"
|
||||
}
|
||||
chain.AddBlock(block)
|
||||
@ -158,25 +157,18 @@ func copyFile(src, dst string) error {
|
||||
return out.Close()
|
||||
}
|
||||
|
||||
func getChain(pack *nt.Package) string {
|
||||
func getBlock(pack *nt.Package) string {
|
||||
num, err := strconv.Atoi(pack.Data)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
size := Chain.Size()
|
||||
if uint64(num) < size {
|
||||
return getBlock(Chain, num)
|
||||
return selectBlock(Chain, num)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getBlock(chain *bc.BlockChain, i int) string {
|
||||
var block string
|
||||
row := chain.DB.QueryRow("SELECT Block FROM BlockChain WHERE Id=$1", i+1)
|
||||
row.Scan(&block)
|
||||
return block
|
||||
}
|
||||
|
||||
func getLastHash(pack *nt.Package) string {
|
||||
return bc.Base64Encode(Chain.LastHash())
|
||||
}
|
||||
@ -185,6 +177,13 @@ func getBalance(pack *nt.Package) string {
|
||||
return fmt.Sprintf("%d", Chain.Balance(pack.Data))
|
||||
}
|
||||
|
||||
func selectBlock(chain *bc.BlockChain, i int) string {
|
||||
var block string
|
||||
row := chain.DB.QueryRow("SELECT Block FROM BlockChain WHERE Id=$1", i+1)
|
||||
row.Scan(&block)
|
||||
return block
|
||||
}
|
||||
|
||||
func addTransaction(pack *nt.Package) string {
|
||||
var tx = bc.DeserializeTX(pack.Data)
|
||||
if tx == nil || len(Block.Transactions) == bc.TXS_LIMIT {
|
||||
@ -197,9 +196,9 @@ func addTransaction(pack *nt.Package) string {
|
||||
go func() {
|
||||
block := *Block
|
||||
IsMining = true
|
||||
res := Chain.AcceptBlock(User, &block, BreakMining)
|
||||
res := (&block).Accept(Chain, User, BreakMining)
|
||||
IsMining = false
|
||||
if res != nil && bytes.Equal(block.PrevHash, Block.PrevHash) {
|
||||
if res == nil && bytes.Equal(block.PrevHash, Block.PrevHash) {
|
||||
Chain.AddBlock(&block)
|
||||
pushBlockToNet(&block)
|
||||
}
|
||||
|
||||
11
values.go
11
values.go
@ -15,12 +15,11 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
GET_SIZE = "[GET_SIZE]"
|
||||
ADD_BLOCK = "[ADD_BLOCK]"
|
||||
GET_CHAIN = "[GET_CHAIN]"
|
||||
GET_LASTHASH = "[GET_LASTHASH]"
|
||||
GET_BALANCE = "[GET_BALANCE]"
|
||||
ADD_TRANSACTION = "[ADD_TRANSACTION]"
|
||||
ADD_BLOCK = iota + 1
|
||||
ADD_TRNSX
|
||||
GET_BLOCK
|
||||
GET_LHASH
|
||||
GET_BLNCE
|
||||
)
|
||||
|
||||
func userNew(filename string) *bc.User {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user