比特币地址的生成过程

https://www.jianshu.com/p/a4167f189029

类CCriticalSection的对象表示一个“临界区”,它是一个用于同步的对象,同一时刻只允许一个线程存取资源或代码区

LOCK是一个宏定义,定义内容

#define LOCK(cs) CCriticalBlockPASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)

LOCK(cs_args)即保证在该代码后面的全局变量在程序运行过程中不会被其他线程对其后的变量进行篡改

程序利用mapArgs,mapMultiArgs传递参数,mapArgs存储单个值,mapMultiArgs存储多个值。

比特币源码研读(23)-地址,密钥(1)

96

electroman

2018.04.29 23:02 字数 352 阅读 75评论 0喜欢 0

比特币地址的生成过程

今天我们先看如何从操作系统获得随机数

获得随机数的文件是:random.h,random.cpp

其中GetStrongRandBytes函数为获得系统随机数的函数

比特币程序通过三种方法获得随机源:1 从OpenSSL中获得;2 从OS 中获得;3,从硬件中获得

其流程如下:

第一个随机源的获得

   // First source: OpenSSL's RNG

   RandAddSeedPerfmon();

   GetRandBytes(buf, 32);

   hasher.Write(buf, 32);

函数RandAddSeedPerfmon是从设备的dev/urandom中获得种子,如果是linux系统,则不需要执行这个函数

   GetRandBytes(buf, 32);函数实现如下:

void GetRandBytes(unsigned char* buf, intnum)

{

   if (RAND_bytes(buf, num) != 1) {

       RandFailure();

    }

}

其中RAND_bytes函数是获得一个随机数的函数

第二个随机源的获得

   // Second source: OS RNG

   GetOSRand(buf);  得到系统熵的32位数据

hasher.Write(buf,32);

第三个随机源的获得

   // Third source: HW RNG, if available.

   if (GetHWRand(buf)) {

       hasher.Write(buf, 32);

}

这个是可选项,如果能获得硬件随机源,则加入这个种子,提高随机性

合并随机源

   // Combine with and update state

    {

       std::unique_lock lock(cs_rng_state);

       hasher.Write(rng_state, sizeof(rng_state));

       hasher.Write((const unsigned char*)&rng_counter,sizeof(rng_counter));

       ++rng_counter;

       hasher.Finalize(buf);

       memcpy(rng_state, buf + 32, 32);

}

输出随机数

   // Produce output

   memcpy(out, buf, num);

   memory_cleanse(buf, 64);

作者:electroman

CCriticalSection是对关键段CRITICAL_SECTION的封装。

关键段(critival section)是一小段代码,他在执行之前需要独占对一些共享资源的访问权。这种方式可以让多行代码以“原子方式”来对资源进行操控。这里的“原子方式”,指的是代码知道除了当前线程之外没有其他任何线程会同时访问该资源。当然,系统仍然可以暂停当前线程去调度其他线程。但是,在当前线程离开关键段之前,系统是不会去调度任何想要访问同一资源的其他线程的。

例如:如果两个线程同时访问一个链表,一个线程可能会在另一个线程搜寻元素的同时向链表中添加一个元素,将导致搜索结果不正确;还有可能两个线程同时向链表中添加元素,这种情况会变的更加混乱;甚至一个线程搜索的时候,另一个线程删除了链表节点,将直接导致程序崩溃。

解决这个问题,我们可以先在代码中定义一个CRITICAL_SECTION数据结构m_sect,然后把任何需要访问共享资源的代码放在EnterCriticalSection和LeaveCriticalSection之间。

    EnterCriticalSection(&m_sect);
    // 共享资源的代码段....
     
    LeaveCriticalSection(&m_sect);


一个 CRITICAL_SECTION结构就像是飞机上的一个卫生间,而马桶则是我们想要保护的资源(用EnterCriticalSection和LeaveCriticalSection组成的围墙包围住“马桶”)。由于卫生间很小,因此在同一时刻只允许一个人在卫生间内使用马桶(在同一时刻只允许一个线程在关键段中使用被保护资源)。

如果有多个总是应该在一起使用的资源,那么我们可以把他们放在同一个“卫生间”中:只需要创建一个CRITICAL_SECTION结构来保护所有这些资源。

关于关键段,需要掌握以下几点:

1、任何要访问共享资源的代码,都必须包含在EnterCriticalSection和LeaveCriticalSection之间。如果忘了哪怕是一个地方,共享资源就有可能被破坏。忘记调用EnterCriticalSection和LeaveCriticalSection,就好像是未经许可就强制进入卫生间一样,线程强行进入并对资源进行操控。只要有一个线程有这种粗暴的行为,资源就会被破坏。

2、关键段CRITICAL_SECTION是个未公开的结构,因为Microsoft认为开发人员不需要理解这个结构的细节。对我们来说,不需要知道这个结构中的成员变量,我们绝对不应该在编写代码的时候用到他的成员。

3、为了对CRITICAL_SECTION结构进行操控,我们必须调用Windows API函数,传入结构的地址。(注意是地址!)也就是说,如果该CRITICAL_SECTION结构生命周期没有结束,那么可以将该结构地址通过自己喜欢的任何方式传给任何线程。

4、在任何线程试图访问被保护的资源之前,必须对CRITICAL_SECTION结构的内部成员进程初始化。我们不知道内部成员,但可以调用Windows函数实现:VOID WINAPI InitializeCriticalSection(__out LPCRITICAL_SECTION lpCriticalSection);

5、当线程不再需要访问共享资源的时候,应调用下面的函数来清理该结构:VOID WINAPI DeleteCriticalSection(__inout LPCRITICAL_SECTION lpCriticalSection);

6、其实CRITICAL_SECTION并不知道什么是共享资源,也不会智能保护共享资源。其根本是,同一个时刻如果有多个线程调用EnterCriticalSection的时候,只有一个线程返回,其余线程则暂停执行,等待前面线程调用LeaveCriticalSection之后再执行。

7、可以看出,进入关键段是没有超时设定的,好像永远不会超时。实际上,对EnterCriticalSection的调用也会超时并引发异常。超时的时间长度由下面这个注册表子项中包含的CriticalSectionTimeout值决定:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager

这个值以秒为单位,他的默认值为2592000秒,大约30天。

8、同一个线程可以随便进入用一个关键段N次,也就是说同一个线程调用EnterCriticalSection无论几次都会返回。不同线程是否能够进入关键段,要看EnterCriticalSection的参数(CRITICAL_SECTION结构的地址)之前是否有线程进入过。要记住:飞机上的卫生间有多个,你可以随便进入无人的卫生间,不能进入有人的卫生间。

弄明白了CRITICAL_SECTION之后,使用CCriticalSection非常方便,如虎添翼。看代码:

//头文件

    class CCriticalSection : public CSyncObjet
    {...
    public:
        CRITICAL_SECTION m_sect;
    public:
        BOOL Unlock();
        BOOL Lock();
        BOOL Lock(DWORD dwTimeout);
    ...
    }

 // 构造函数

    CCriticalSection::CCriticalSection() : CSyncObject(NULL)
    {         
        HRESULT hr = S_OK;
        if (!InitializeCriticalSectionAndSpinCount(&m_sect, 0))//可以理解为InitializeCriticalSection,为了效率,加了一个旋转锁。
        {
            hr =  HRESULT_FROM_WIN32(GetLastError());
        }
        
        if (FAILED(hr))
        {
            AtlThrow(hr);
        }        
    }


 

//进入关键段

    BOOL CCriticalSection::Lock()
    {    
        ::EnterCriticalSection(&m_sect);
     
        return TRUE;
    }
     

 // 离开关键段

    BOOL CCriticalSection::Unlock()
    {
        ::LeaveCriticalSection(&m_sect);
        
        return TRUE;
    }


 // 析构

    CCriticalSection::~CCriticalSection()
    {
        ::DeleteCriticalSection(&m_sect);

类CCriticalSection的对象表示一个“临界区”,它是一个用于同步的对象,同一时刻只允许一个线程存取资源或代码区。临界区在控制一次只有一个线程修改数据或其它的控制资源时非常有用。例如,在链表中增加一个结点就只允许一次一个线程进行。通过使用CCriticalSection对象来控制链表,就可以达到这个目的。它就像是一把钥匙,哪个线程获得了它就获得了运行线程的权力,而把其他线程统统阻塞。
CCriticalSection类的构造函数原型如下:
CCriticalSection()

可以发现这个类的构造函数没有参数,所以创建一个CCriticalSecti
 

---------------------
作者:码侬
来源:CSDN
原文:https://blog.csdn.net/gao_zilai/article/details/8079632
版权声明:本文为博主原创文章,转载请附上博文链接!

链接:https://www.jianshu.com/p/09a81311fdbf
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

猜你喜欢

转载自blog.csdn.net/TuxedoLinux/article/details/86437470