区块链工程笔记:UTXO、Solidity 与 Go
结论: 本文是区块链工程专题的原始索引,覆盖三个不同知识域,后续应拆成独立文章。
内容状态: 竞赛学习笔记,不代表生产级实现;密码学、交易签名和合约代码必须经过测试与审计。
UTXO
-
outPutTxid要写Txid前缀
-
挖矿奖励inputTxid为nil,索引为-1.地址为nil
-
input = output,如果转账后有余额,必须转账给自己
-
如果有多个input,要按从左往右的顺序写入
Solidity 合约
常用代码
关键字
- pragma solidity : 开头声明版本
- contract: 合约开头
- constructor: 声明构造函数,注意与contract区分,太长难以记住可以分为con-struct-or
- require: 用于确认条件是否满足,使用格式为:
1
2
3
4
5function fun() public {
require(条件语句,"字符串,可不写")
}
示例:
require(a == 1,"a不等于1") - modifier: 函数修饰器,可以在函数执行前自动检查某个条件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15pragma solidity ^0.4.20;
contract h {
address owner ;
int public a = 1;
constructor () public {
owner = msg.sender;///获取合约发起者的地址
}
modifier Own{
require( owner == msg.sender,"");///判断当前函数调用者的地址是否等于owner
_;//横杠一定要写,它表示了被修饰的函数的运行位置,这里在requir之后,若require失败则不运行
}
function fun() Own public {
a = 10;
}
}
状态变量
- msg.sender:solidity的状态变量,用于获取当前合约/函数的调用者地址,常用在构造函数中获取合约发起者的地址
- block.timestamp(): 获取时间戳,类型为uint
合约部署
从构造函数constructor看
go技术代码
go version //查看版本
go env _w GO111MODULE=on / /开启环境变量
go env //查看库文件
go get -u golang.org/x/crypto/x/base58/… //拉取库文件
go.mod文件
运行代码和使用外部库需要使用go.mod文件,可以在vscode集成终端中输入命令创建:
1 | go mod init [项目名] |
时间戳
- 时间戳转换日期:
使用unix函数1
2
3
4
5
6//1620221103转换
t := time.Unix(int64(1620221103), 0)
fmt.Println(t)
//2021-05-05 21:25:03 +0800 CST
//CST表示中国时间,+0800表示时差,想要转换成世界协调UTC可以:
//2021-05-05 13:25:03 +0000 UTC - 计算时间差:
使用sub函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31//时间戳 (1666194910) 与 时间戳 (1628202212)相差总秒/总分...
t1 := time.Unix(int64(1666194910), 0)
t2 := time.Unix(int64(1628202212), 0)
dT := t1.Sub(t2)
s := dT.Seconds() //算相差总秒数
fmt.Println(s)
//37992698
m := dT.Minutes() //算相差总分钟
fmt.Println(m)
//633211.6333333333
h := dT.Hours() //算相差总小时
fmt.Println(h)
//10553.527222222223
d := dT.Hours() / 24 //算相差总天数
fmt.Println(d)
//439.730300925926 取整数位
//算日期是那年的第几天
yearday := time.Unix(1666194910, 0).YearDay()
fmt.Println(yearday)
//292
//求相差()天()时()分()秒无敌求法
qijie := time.Unix(1666194910-1628202212, 0).UTC()
fmt.Println(qijie) //妙算时分秒差,天数差用Day := dT.Hours()/24
//1971-03-16 17:31:38 +0000 UTC,day = 439.730300925926
//说明两天相差了439天,17小时,31分,38秒
//.UTC()转换为世界协调时,因为中国有时差,转换后时间差不对
加密算法
- md5:
1
2
3
4
5
6
7
8
9
10//直接加密
data := []byte{1} //待加密数据,如果类型不是[]byte需要强转
hash := md5.Sum(data) //md5加密
fmt.Println(hash)
//先new再write加密
md := md5.New() //new
md.Write(data) //写入待加密数据
hash := md.Sum(nil) //在加密后的数据前拼接nil,即不拼接
fmt.Println(hash2) - RIPEMD160:
用法类似md5的第二种用法,使用前需导入“golang.org/x/crypto/ripemd160”1
2
3
4
5data := []byte{1}
RIP := ripemd160.New() //新建
RIP.Write(data) //写入待加密数据
riped := RIP.Sum(nil)
fmt.Print(riped) - sha:
sha有sha224,256等,用法类似1
2data := []byte{1}
sha256.Sum256(data)
编码
gob:
1 | //编码 |
base64:
base64可能会与rsa加密、签名一起出现,但题目可能未提及,需要自己记住去解码
1 | //将[]byte数据编码为string |
base58:
直接encode/decode就好了
1 | data := []byte{1, 2, 3} //待编码数据 |
文件存储
读取文件:
1 | //使用os.OpenFile() |
写入文件:
1 | //使用os.OpenFile() |
公私钥
从pem文件解析公私钥
pem目前遇见的有ecdsa和rsa两种算法,可以从密钥文件的内容直接看出,两种密钥的解析方法一样,但对于ecdsa公钥需要拼接一次
1 | //解析rsa公钥 |
生成ecdsa密钥
1 | privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) //生成私钥 |
生成钱包地址
钱包地址的生成需要以下几个步骤
- 生成密钥对
- publicHash = ripemd160(sha256(publicKey))。获取公钥哈希
- _21byte = Version + publicHash。拼接版本号(默认写0x00)和公钥哈希
- checkSum = sha256(sha256(_21byte))【:4】。哈希后取前4个字节
- —25byte = —21byte + checkSum
- address = base58(_25byte)。base58编码
1 | privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) //生成私钥 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 梦溪笔谈!
评论