0%

之前已经在x86的mac电脑上编译过substrate,按照官方指南上的操作就可以正常编译。但是在新款m1电脑上并没有编译通过,现在重新尝试在m1上编译substrate。

主要的准备过程参考如下文章

https://zhuanlan.zhihu.com/p/337224781

不过参考文章写于2020年12月16日,到现在(2021年3月10日)有部分状况已经发生了变化。针对和文章中不一样的状况稍作说明。

RUST

rust环境现在可以直接支持m1。所以使用rustup脚本可以直接安装rust,不需要额外设置。安装完成之后使用

rustup show

查看toolchain。则会发现是以aarch64开头的,原来的x86下面的tool-chain是

stable-x86_64-apple-darwin (default)

注意差别。

阅读全文 »

Sqlite自增字段

起因:在使用数据库存储从区块链网络上取来的block_header时,block_header本身并不带自身的高度信息。不过取来的数据是经过筛选的,按照数据库存储的顺序就可以代表blockheader的高度。所以在数据库中增加一个id primiry key autoincrement 的自增主键。每次从数据库查询时获取id值来代表区块的高度。但后来重构,id被TEXT类型的逐渐替代,所以这个功能无法正常实现。所以产生以下疑问

在已经有TEXT类型的主键后,sqlite可以拥有别的自增字段吗?

不可以!在sqlite的文档FAQ中第一个问题(文末给出参考链接)就是关于如何设置自增字段的。在sqlite中自增约束AUTOINCREMENT只可以跟在PRIMARY KEY后面。把AUTOINCREMENT放在主键以外的地方是不可以的。或者再明确一点,要想在sqlite中拥有一个自增字段必须这样写

1
id INTEGER PRIMARY KEY AUTOINCREMENT,

要求id的类型必须是INTEGER。每次插入数据库的时候,不要插入id的数据,数据库会自动为我们的主键id实现自增。之前提到的情况:id已经是TEXT PRIMARY KEY的状态下,无法再拥有另一个自增字段了。

题外:在sqlite以外的数据库中是可以的。以mysql为例,mysql的AUTOINCREMENT是可以加在主键之外的地方的。一个表中,只允许有一个自增字段,而且在mysql中需要给主键以外的字段实现自增,必须给该字段加上unique约束。

注意点:

  1. 在设定id INTEGER PRIMARY KEY,不加AUTOINCREMENT,只要不指定插入id的数据,id字段也可以实现自增。

在已经有TEXT类型的主键后,一定要有一个自增的字段来记录当前所在的行数怎么办?

阅读全文 »

多线程原语CondVar

多线程下的原语,除了我们常用的锁,还有另外一类用于同步的原语叫做“屏障”,“条件变量”(在rust或者cpp中)。在其他语言中也有类似的概念,叫做栅栏,闭锁,屏障,信号量等。他们具有相同的意义。

在介绍条件变量之前,先介绍屏障(Barrier)。屏障相当于一堵带门的墙,使用wait方法,在某个点阻塞全部进入临界区的线程。条件变量(Condition Variable)和屏障的语义类似,但它不是阻塞全部线程,而是在满足某些特定条件之前阻塞某一个得到互斥锁的线程。

单纯讲条件变量的意义并不直观。换种描述

条件变量可以在我们达到某种条件之前阻塞线程,我们利用此特性可以对线程进行同步。或者说做到按照某种条件,在多个线程中达到按照特定顺序执行的目的。

为此我们设计如下下面流程。为此流程写一段代码,来体会条件变量的作用

我们启动三个线程,t1,t2,t3。分别执行任务T1,T2,T3。现在要求:T2必须等待T1和T3完成之后再执行

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use parking_lot::{Mutex, Condvar};
use std::sync::Arc;
use std::thread;
use std::thread::sleep;
use std::time::Duration;


pub fn main() {
let pair = Arc::new((Mutex::new(0),
Condvar::new()));
let pair2 = pair.clone();
let pair3 = pair.clone();


let t1 = thread::Builder::new()
.name("T1".to_string())
.spawn(move ||
{
sleep(Duration::from_secs(4));
println!("I'm working in T1, step 1");
let &(ref lock, ref cvar) = &*pair2;
let mut started = lock.lock();
*started += 2;
cvar.notify_one();
}
)
.unwrap();

let t2 = thread::Builder::new()
.name("T2".to_string())
.spawn(move ||
{
println!("I'm working in T2, start");
let &(ref lock, ref cvar) = &*pair;
let mut notify = lock.lock();

while *notify < 5 {
cvar.wait(&mut notify);
}
println!("I'm working in T2, final");
}
)
.unwrap();

let t3 = thread::Builder::new()
.name("T3".to_string())
.spawn(move ||
{
sleep(Duration::from_secs(3));
println!("I'm working in T3, step 2");
let &(ref lock, ref cvar) = &*pair3;
let mut started = lock.lock();
*started += 3;
cvar.notify_one();
}
)
.unwrap();

t1.join().unwrap();
t2.join().unwrap();
t3.join().unwrap();
}

以上代码可以在 这个链接 下在playground运行。

上面的代码需要注意的点如下

阅读全文 »

Jni符号表

本文是之前博客文章

《使用rust写安卓库》

的延续。之前的文章主题是如何利用rust-jni库提供便于java使用的rust jni代码。本文在之前的基础上继续提供后续关于jni符号,或者type的说明。

阅读全文 »

比特币是不是货币

今天晚上和人聊天的时候,提到的了这个话题。我开始从事比特币相关开发也有一段时间了,经常有人会提到这个话题。这个话题比”比特币是什么?”更加具体,我也被问到过多次。本着不重复劳动的初心,特意写这篇小文章来说说我的理解。

阅读全文 »

使用rust写安卓库

rust写安卓库也是rust的一个重要应用方向,之前用来写安卓的库的语言大多数都是c/c++。本文不讨论两种(或者叫两类)语言的优劣,只说明如何搭建一个rust-android相互交互的环境。

阅读全文 »

从零构建一个SPV钱包其一

开篇

这是如何从零开始构建一个SPV钱包的开篇文章的第一篇,按照行文习惯,先列出系列文章的目的:

阅读全文 »

rust工程实践

本文是rust的实践记录,主要用来记录rust写工程代码,和在tikv的talent-plan中学习到的代码常识。这里列出的是比较重要,但是不足以写一篇文章来讨论的。长期更新。以后考虑加个目录方便查询。

阅读全文 »