实验语言:GO
实验环境:GoLand 2022.1 ; go 1.13.4.widows-amd64.msi ;curl-7.83.1
实验中使用的开源包:
http://github.com/davecgh/go-spew/spew;http://github.com/gorilla/mux;http://github.com/joho/godotenv;
实验中使用的工具包:
"crypto/sha256"“encoding/hex”“encoding/json”“fmt”“io”“log”“net/http”“os”“strconv”“strings”“sync”"time”
实验中的网络端口:http://localhost:8080
目录:
文章目录
1.基于pow算法挖矿并实现区块链的基本功能
2.基于LevleDB实现数据的KV存储
对等网络,即对等计算机网络,是一种在对等者之间分配任务和工作负载的分布式应用架构,网络的参与者共享他们所拥有的一部分硬件资源(处理能力、存储能力、网络连接能力、打印机等),这些共享资源通过网络提供服务和内容,能被其它对等节点直接访问而无需经过中间实体。在此网络中的参与者既是资源、服务和内容的提供者,又是资源、服务和内容的获取者。
与大多数货币不同,比特币不依靠特定货币机构发行,它依据特定算法,通过大量的计算产生,比特币经济使用整个P2P网络中众多节点构成的分布式数据库来确认并记录所有的交易行为,并使用密码学的设计来确保货币流通各个环节的安全性。P2P的去中心化特性与算法本身可以确保无法通过大量制造比特币来人为操控币值。基于密码学的设计可以使比特币只能被真实的拥有者转移或支付。
区块链,就是一个又一个区块组成的链条。每一个区块中保存了一定的信息,它们按照各自产生的时间顺序连接成链条。这个链条被保存在所有的服务器中,只要整个系统中有一台服务器可以工作,整条区块链就是安全的。这些服务器在区块链系统中被称为节点,它们为整个区块链系统提供存储空间和算力支持。如果要修改区块链中的信息,必须征得半数以上节点的同意并修改所有节点中的信息,而这些节点通常掌握在不同的主体手中。
区块有两种,一个是普通区块,一个就是创世区块。创世区块就是一项区块链项目中的第一个区块。
配置环境


声明变量
//区块结构体
type Block struct
{
PreHash string
Hashcode string
TimeStamp string
Diff int
Value string
Index int
Nonce int
}
//区块链链表
type lian_my struct {
NextNode *lian_my
Data *BLOCK.Block
}
这一步用于根据比特币定义我们的哈希值以及新的链表
func GenerationHashValue(block Block) string {
var hashdata = strconv.Itoa(block.Index) + strconv.Itoa(block.Nonce) + strconv.Itoa(block.Diff) + block.TimeStamp
var hashmy = sha256.New()
hashmy.Write([]byte(hashdata))
hashed := hashmy.Sum(nil)
return hex.EncodeToString(hashed)
}
func GenerateNextBlock(data string, oldBlock Block) Block {
var newBlock Block
newBlock.TimeStamp = time.Now().String()
newBlock.Diff = 3
newBlock.Index = oldBlock.Nonce + 1
newBlock.Value = data
newBlock.PreHash = oldBlock.Hashcode
newBlock.Nonce = 0
newBlock.Hashcode = pow(newBlock.Diff, &newBlock)
return newBlock
}
func GenerateFirstBlock(data string) Block {
var chuangshi Block
chuangshi.PreHash = "0"
chuangshi.TimeStamp = time.Now().String()
chuangshi.Diff = 3
chuangshi.Value = data
chuangshi.Index = 1
chuangshi.Nonce = 0
chuangshi.Hashcode = GenerationHashValue(chuangshi)
return chuangshi
}
//pow工作量证明
func pow(diff int, block *Block) string {
for {
hashmy := GenerationHashValue(*block)
if strings.HasPrefix(hashmy, strings.Repeat("0", diff)) {
return hashmy
fmt.Println("挖到了一个区块")
} else {
block.Nonce++
}
}
}
函数传入指针,这个相当于是在不断的挖矿,for是一个死循环,用block的信息生成一个哈希值,判断这一次的哈希值是否前面的0满足diff,这里可以直接使用hasprefix()函数来进行判断,相当的方便。
//创建头节点,保存创世区块
func CreaterHeader(data *BLOCK.Block) *lian_my {
headerNode := new(lian_my)
headerNode.NextNode = nil
headerNode.Data = data
return headerNode
}
//添加下一个结点
func Addnode(data *BLOCK.Block, node *lian_my) *lian_my {
var newNode *lian_my = new(lian_my)
newNode.NextNode = nil
newNode.Data = data
node.NextNode = newNode
return newNode
}
//展示当前所有节点
func ShowNodes(node *lian_my) {
n := node
for {
if n.NextNode == nil {
fmt.Println(n.Data)
break
} else {
fmt.Println(n.Data)
n = n.NextNode
}
}
}

leveldb是谷歌两位工程师使用C++实现的k-v存储系统,我们这里希望使用go进行复现, 属于按照key和value存储,用户也是可以重写排序函数,包含了最基本的数据操作接口,put,get,delay.同时多次操作可以认为是一次原子操作,可以用于支持事务。
type DB struct {
path string
data map[string][]byte
}
这里path(字符串类型)用于存储连接的地址,data(byte类型)用于存储kv的键值
type Iterator interface {
Next() bool
Key() []byte
Value() []byte
}
type myIterator struct {
data []Pair
index int
length int
}
NEXT判断是否下一个有值, key和value用于遍历键值
type Pair struct {
Key []byte
Value []byte
}
func NewDefaultIterator(data map[string][]byte) *myIterator {
my := new(myIterator)
my.index = -1
my.length = len(data)
for k, v := range data {
p := Pair{[]byte(k),
v,
}
my.data = append(self.data, p)
}
return my
}
初始化迭代器的默认值并进行遍历
func (self *myIterator) Next() bool {
if self.index < self.length-1 {
self.index++
return true
}
return false
}
func (self *myIterator) Key() []byte {
if self.index == -1 || self.index >= self.length {
panic(fmt.Errorf("INDEXOUTOFBOUNDERROR"))
}
return self.data[self.index].Key
}
func (self *myIterator) Value() []byte {
if self.index >= self.length {
panic(fmt.Errorf("INDEXOUTOFBOUNDERROR"))
}
return self.data[self.index].Value
}
实现下一个是否存在,以及返回value 和key
func New(path string) (*DB, error) {
my := DB{
path: path,
data: make(map[string][]byte),
}
return &my, nil
}
func (my *DB) Put(key []byte, value []byte) error {
my.data[string(key)] = value
return nil
}
func (my *DB) Get(key []byte) ([]byte, error) {
if v, ok := my.data[string(key)]; ok {
return v, nil//如果有则说明可以直接使用
} else {//如果返回为空,则说明没有
return nil,
fmt.Errorf("Not Found")
}
}
func (self *DB) Del(key [](byte)) error {
if _, ok := self.data[string(key)]; ok {
delete(self.data, string(key))
return nil
} else {
return fmt.Errorf("not Found")
}
}
import (
"fmt"
"testing"
)
//迭代器测试
func TestNewDefaultIterator(t *testing.T) {
data := make(map[string][]byte)
data["K1"] = []byte("V1")
data["K2"] = []byte("V2")
data["K3"] = []byte("V3")
data["K4"] = []byte("V4")
my := NewDefaultIterator(data)
if my.length != 3 {
t.Fatal()
}
for iter.Next() {
fmt.Printf("%s : %s\n", my.Key(), string(my.Value()))
}
}
测试结果
func Test_leveldb(t *testing.T) {
db, err := New("")
check(err)
err = db.Put([]byte("k1"), []byte("v1"))
check(err)
err = db.Put([]byte("k4"), []byte("v4"))
check(err)
err = db.Put([]byte("k2"), []byte("v2"))
check(err)
err = db.Put([]byte("k1"), []byte("v1"))
check(err)
err = db.Put([]byte("k8"), []byte("v8"))
check(err)
v, err := db.Get([]byte("k8"))
fmt.Printf("%s\n\n", v)
if !bytes.Equal(v, []byte("v8")) {
t.Fatal()
}
v, err = db.Get([]byte("k1"))
if !bytes.Equal(v, []byte("v1")) {
t.Fatal()
}
//err = db.Del([]byte("k1"))
//check(err)
iter := db.Iterator()
for iter.Next() {
fmt.Printf("%s - %s \n", string(iter.Key()), string(iter.Value()))
}
}
func check(err error) {
if err != nil {
panic(err)
}
}



1.可以在网络端POST指令访问,添加新的比特币交易区块。
2.可以在网络端GET指令访问,查看所有已经添加的交易信息。
1.实验中使用的开源包:
http://github.com/davecgh/go-spew/spew;
http://github.com/gorilla/mux;
http://github.com/joho/godotenv;
开源包功能:编写web程序的软件包,在控制台格式化输出结果,配置编写.env文件
注:基本代码和前两部分相同,但在下面处存在区别
var Blockchain []Block
var mutex = &sync.Mutex{}
上锁,并且有数组进行存储,同时在有效判别函数中,会抓取所有节点,寻找最长的链,来进行写入。但是在本次试验中因为我在本地并没有其他人的加入,所以我就用简单的python语言大概简述。
def resolve(self) ->bool:
fujin=self.nodes
new_chain = None
max_length = len(self.chain)
for node in fujin:
get new_length
if new_legth>max_length. and ishashvaild(self)
max_length=length
new_chain=chain
if new_chain:
self.chain = new_chain
return true
return false
//http启动
func run() error {
mux := makeMuxRouter()
httpAddr := os.Getenv("ADDR")
log.Println("listening on", os.Getenv("ADDR"))
s := &http.Server{
Addr: ":" + httpAddr,
Handler: mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
if err := s.ListenAndServe(); err != nil {
return err
}
return nil
}
func makeMuxRouter() http.Handler {
muxRouter := mux.NewRouter()
muxRouter.HandleFunc("/", handgetblockhain).Methods("GET")
muxRouter.HandleFunc("/", handerwriteblock).Methods("POST")
return muxRouter
}
func handgetblockhain(w http.ResponseWriter, r *http.Request) {
bytes, err := json.MarshalIndent(Blockchain, "", "\t")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
io.WriteString(w, string(bytes))
}
func isblockivaild(newBlock, oldblock Block) bool {
if oldblock.Index+1 != newBlock.Index {
return false
}
if oldblock.HashCode != newBlock.PreHash {
return false
}
if calculationHash(newBlock) != newBlock.HashCode {
return false
}
return true
}
论证是否是旧的区块+1,以及哈希值是否对应
//声明一个post类型的数据类型
type Message struct {
BPM int
}
func handerwriteblock(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Content-Type", "application/json")
var message Message
decoder := json.NewDecoder(request.Body)
if err := decoder.Decode(&message); err != nil {
respondWithJson(writer, request, http.StatusNotFound, request.Body)
return
}
defer request.Body.Close()
//生成区块
mutex.Lock()
newblock := generateBlock(Blockchain[len(Blockchain)-1], message.BPM)
mutex.Unlock()
//判断是否合法
if isblockivaild(newblock, Blockchain[len(Blockchain)-1]) {
Blockchain = append(Blockchain, newblock)
spew.Dump(Blockchain)
}
respondWithJson(writer, request, http.StatusCreated, newblock)
}
func respondWithJson(writer http.ResponseWriter, request *http.Request, code int, inter interface{}) {
writer.Header().Set("Content-Type", "application/json")
//格式化输出JSON
response, err := json.MarshalIndent(inter, "", "\t")
if err != nil {
writer.WriteHeader(http.StatusInternalServerError)
writer.Write([]byte("HTTP 500:Serve Error"))
return
}
writer.WriteHeader(code)
writer.Write(response)
}
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal(err)
}
go func() {
genesisblock := Block{}
genesisblock = Block{
0, time.Now().String(), 0, calculationHash(genesisblock),
"", differculty, 0}
mutex.Lock()
Blockchain = append(Blockchain, genesisblock)
mutex.Unlock()
spew.Dump(genesisblock)
}()
log.Fatal(run())
}
ADDR= 8080
curl -H "Content-Type: application/json" -X POST -d"{\"BPM\":10}"“http://localhost:8080”
curl http://localhost:8080
发送指令
播在局域网中
发送被希望记录的交易信息
挖到矿后将其加入了区块链
我个人是还想使用bee-go metaMast做一个使用区块链交易界面的,但是还是因为个人的问题,代码在golang的前端部分已经完善,但在remix智能公约部分陷进去,出不来了。所以我简要的附上几张图,工程文件里的view会附上我的html css文件。
首页 |
查询 |
智能合约 |
beego |
在长达两个月的时间,我从GO语言的小白到可以逐步完善自己的想法,从只知道区块链可以炒股到逐渐对其中的原理有了更深的理解,尤其是在广播时候的代码,因为比特币公开的源代码是用c++编写的,所以用go浮现的时候就有了颇多困难。尤其是开发智能合约到最后还要学Solidity语言。
因为之前一直都在TI杯比赛中接触代码,但是比赛中大多数都是基于嵌入式环境的硬件系统,无论是ARDUINO,STM32还是ESP82266的开发虽然在调试上但是其中的编程语言都是基于C的,GO和css则完全是面向对象的,尤其是Golang的go get,每次下载一个包都是困难重重,无法cloning竟然还和内网有关。
但是面向对象的有趣在于可以大大减少程序员的调试难度,思路也更有逻辑性。暑假里 我一定要彻底完成我自己的以太坊彩票站。
也感谢沈老师和蔺老师在课堂上对于网络安全的讲解,让我认识到安全学科已经成为了新的行业热门,也了解到网络安全对于社会生产的重要性。
本实验中的代码均已开源在github;本说明文档首发于个人博客
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复