• 62、solidity环境搭建、编译及编写合约-3——2020年07月12日12:55:51


    2020年07月12日12:59:00

    2019年09月27日14:15:32

    1.通过solc工具编译合约

    1.1 先在vscode里创建sol文件

    pragma solidity ^0.4.24;
    	contract Immo{
        address public ceo;
        constructor() public {
          ceo=msg.sender;
        }
        
      }
    

    1.2.准备编译环境,sol文件都是通过solc工具编译的

    npm install solc@0.4.24 --save一定要声明版本

    github.com/ethereum/solc-js

    1.3.项目是通过react新建的

    create-react-app imooc-on-blockchain

    1.4.js脚本文件读写和编译sol

    mkdir scripts

    touch compile.js

    // 文件模块
    const fs = require('fs')
    
    const path = require('path')
    //编译模块solc
    const solc = require('solc')
    
    const contractPath = path.resolve(__dirname,'../contracts/Imooc.sol')
    
    // 获取合约文件内容
    const source = fs.readFileSync(contractPath,'utf-8')
    // 编译
    const ret = solc.compile(source)
    // console.log(ret)
      Object.keys(ret.contracts).forEach(name=>{
        //过滤掉第一个key键,它前面有一个:,不需要
        const contractName = name.slice(1)
        //创建即将要写进数据的文件路径
        const filePath = path.resolve(__dirname, `../src/compiled/${contractName}.json`)
        //同步写数据
        fs.writeFileSync(filePath,JSON.stringify(ret.contracts[name]))
        console.log(`${filePath} bingo`)
      })
    
    // arr = [{name:'react',content:'xx',{name:'vue',content:'xx'}]
    

    1.5.配置package.json

    "compile" :"node scripts/compile.js"

    image-20190927150058197

    1.6.启动服务

    npm run compile

    编译.sol文件,生成一个json(后面部署,测试等需要这些数据)

    1. bytecode

      部署合约用的数据

    2. interface接口声明

      测试使用

    2.合约自动编译

    1. 每次compile清空文件,重新生成
    2. 报错信息打印
    3. 能监听,自动compile

    2.1 安装rimraf清除模块

    npm install rimraf --save

    配置package.json

    rimraf src/compiled/* && node scripts/compile.js

    2.2 控制报错信息

    打印出error,发现errors数组长度>1

    image-20190927152634081

    则:

    if(Array.isArray(ret.errors) && ret.errors.length>0){
      // 出错了
      console.log(ret.errors[0])
    }else{
      Object.keys(ret.contracts).forEach(name=>{
        const contractName = name.slice(1)
        const filePath = path.resolve(__dirname, `../src/compiled/${contractName}.json`)
        fs.writeFileSync(filePath,JSON.stringify(ret.contracts[name]))
        console.log(`${filePath} bingo`)
      })
    }
    

    再调式的时候会出现:

    image-20190927152948353

    2.3 使用钩子precompile

    在package.json文件中

    precompile:"rimraf src/compiled/*"

    2.4 监听——使用Onchange模块

    npm install onchange --save

    "precompile": "rimraf src/compiled/* ",
    "compile": "node scripts/compile.js",
    "precompile:w": "npm run compile",
    "compile:w": "onchange 'contracts/*.sol' -- npm run compile"
    

    只要合约发生了变化,就会重新编译

    npm run compile:w

    3.编写合约——课程列表

    3.1 两个合约:课程数组,单个课程

    3.2 方法:新建课程,获取课程

    3.3 代码

      pragma solidity ^0.4.24;
      
      contract CourseList{
      address public ceo;
      address[] public courses;
      constructor() public {
        ceo = msg.sender;
      }
    
      function createCourse(string _name) public{
        address newCourse = new Course(ceo,msg.sender, _name);
        courses.push(newCourse);
      }
      // 获取课程所有地址
      function getCourse() public view returns(address[]){
        return courses;
      }
        }
    
         contract Course{
            string public name;
            constructor(string _name) public {
                name=_name;
                        }
            }
    

    4.测试合约

    4.1 虚拟节点

    ganache-cli

    4.2测试用的模块

    mocha

    4.3 编写测试用例
    const path = require('path');
    const assert = require('assert');
    
    describe('测试课程的智能', () => {
    
        it('测试1+2是否等于3', () => {
    
            assert.equal(1 + 2, 3);
        })
    })
    
    4.4 测试合约方法
    const path = require('path');
    const assert = require('assert');
    const Web3 = require('web3')
    const ganache = require('ganache-cli')
    //const BigNumber = require('bignumber.js')
    const web3 = new Web3(ganache.provider())
    // 引入合约的json
    const CourseList = require(path.resolve(__dirname, '../src/compiled/CourseList.json'))
    const Course = require(path.resolve(__dirname, '../src/compiled/Course.json'))
    
    
    // 定义几个全局变量,所有测试都需要
    let accounts
    // 实例
    let courseList
    let course
    
    describe('测试课程的智能', () => {
    
        before(async () => {
            // 测试前的数据初始化
            accounts = await web3.eth.getAccounts()
            
            console.log(accounts)
            // 1. 虚拟部署一个合约
            courseList = await new web3.eth.Contract(JSON.parse(CourseList.interface))
                .deploy({ data: CourseList.bytecode })
                .send({
                    // 最后一个是创建者
                    from: accounts[9],
                    gas: '5000000'
                })
    
        })
    
        it('合约部署成功', () => {
            assert.ok(courseList.options.address)
        })
    
        it('测试添加课程', async () => {
            const oldaddress = await courseList.methods.getCourse().call()
            assert.equal(oldaddress.length, 0)
            await courseList.methods.createCourse(
                '蜗牛的React课程'
            )
                .send({
                    from: accounts[0],
                    gas: '5000000'
                })
            const address = await courseList.methods.getCourse().call()
            assert.equal(address.length, 1)
    				console.log(address)
        })
    
    })
    
    4.5 配置package.json
    "test:w": "mocha --watch"
    
    4.6 运行指令

    npm run test:w

    4.6 测试结果

    image-20190927202842569

    2019年09月27日20:31:07

    5.添加删除课程指令

    5.1 sol文件里函数编写
     function removeCourse(uint _index) public {
         // 只有ceo能删除
        require(msg.sender == ceo);
        // 根据索引删除
        require(_index<courses.length);
      }
    
    5.2 package.json配置
        "rebuild": "npm run compile && mocha",
        "rebuild:w": "onchange 'contracts/*.sol' 'test/*.js' -- npm run rebuild"
    

    作用是当合约发生变化时,先编译再测试。

    5.3 运行

    npm run rebuild

    5.4 测试用例
    const path = require('path');
    const assert = require('assert');
    const Web3 = require('web3')
    const ganache = require('ganache-cli')
    //const BigNumber = require('bignumber.js')
    const web3 = new Web3(ganache.provider())
    // 引入合约的json
    const CourseList = require(path.resolve(__dirname, '../src/compiled/CourseList.json'))
    const Course = require(path.resolve(__dirname, '../src/compiled/Course.json'))
    
    
    // 定义几个全局变量,所有测试都需要
    let accounts
    // 实例
    let courseList
    let course
    
    describe('测试课程的智能', () => {
    
        before(async () => {
            // 测试前的数据初始化
            accounts = await web3.eth.getAccounts()
    
            console.log(accounts)
            // 1. 虚拟部署一个合约
            courseList = await new web3.eth.Contract(JSON.parse(CourseList.interface))
                .deploy({ data: CourseList.bytecode })
                .send({
                    // 最后一个是创建者——重点
                    from: accounts[9],
                    gas: '5000000'
                })
    
        })
    
        it('合约部署成功', () => {
            assert.ok(courseList.options.address)
        })
    
        it('测试添加课程', async () => {
            const oldaddress = await courseList.methods.getCourse().call()
            assert.equal(oldaddress.length, 0)
            await courseList.methods.createCourse(
                '蜗牛的React课程'
            )
                .send({
                    from: accounts[0],
                    gas: '5000000'
                })
            const address = await courseList.methods.getCourse().call()
            assert.equal(address.length, 1)
            console.log(address)
    
        })
    
        it("添加课程的属性", async () => {
            const [address] = await courseList.methods.getCourse().call()
            // 添加的课程合约的地址
            course = await new web3.eth.Contract(JSON.parse(Course.interface), address)
            const name = await course.methods.name().call()
            assert.equal(name, '蜗牛的React课程')
        })
    
    
    
        //删除功能
        it("只能ceo能删", async () => {
            await courseList.methods.createCourse(
                '蜗牛的Vue课程'
            )
                .send({
                    from: accounts[0],
                    gas: '5000000'
                })
            const address = await courseList.methods.getCourse().call()
            assert.equal(address.length, 2)
    
          await courseList.methods.removeCourse(0).send({
            from:accounts[9],
            gas:'5000000'
          })
          const address1 = await courseList.methods.getCourse().call()
          console.log(address1)
          assert.equal(address1.length,1)
          
        })
    
    })
    
    5.6 发现bug

    solidity提供的delete()方法删除了地址账号后,不是清除数据,而是将数据清0.

    所以得修改合约里的方法

    5.7 修改合约
      function removeCourse(uint _index) public {
         // 只有ceo能删除
        require(msg.sender == ceo);
        // 根据索引删除
        require(_index<courses.length);
        uint len = courses.length;
        for(uint i=_index;i<len-1;i++){
          courses[i] = courses[i+1];
        }
        delete courses[len-1];
        courses.length--;
      }
    
    
        }
    
    5.8 添加管理员的认证——合约方法
      function isCeo() public view returns(bool){
        return msg.sender==ceo;
      }
    
    5.9测试用例
      it('判断是不是ceo',async ()=>{
        const isCeo1 = await courseList.methods.isCeo().call({
          from :accounts[9]
        })
        const isCeo2 = await courseList.methods.isCeo().call({
          from :accounts[1]
        })
        assert.ok(isCeo1)
        assert.ok(!isCeo2)
      })
    
    5.10 运行结果

    npm run rebuild:w

    image-20190927234013228

    5.11 完整代码
    //Imooc.sol  
    pragma solidity ^0.4.24;
      
      contract CourseList{
      address public ceo;
      address[] public courses;
      constructor() public {
        ceo = msg.sender;
      }
    
      function createCourse(string _name) public{
        address newCourse = new Course(_name);
        courses.push(newCourse);
      }
      // 获取课程所有地址
      function getCourse() public view returns(address[]){
        return courses;
      }
    
      function removeCourse(uint _index) public {
         // 只有ceo能删除
        require(msg.sender == ceo);
        // 根据索引删除
        require(_index<courses.length);
        uint len = courses.length;
        for(uint i=_index;i<len-1;i++){
          courses[i] = courses[i+1];
        }
        delete courses[len-1];
        courses.length--;
      }
      function isCeo() public view returns(bool){
        return msg.sender==ceo;
      }
    
        }
         
         
         
    contract Course{
        string public name;
        constructor(string _name) public {
            name=_name;
                 }
            }
    
    //course.spec.js
    const path = require('path');
    const assert = require('assert');
    const Web3 = require('web3')
    const ganache = require('ganache-cli')
    //const BigNumber = require('bignumber.js')
    const web3 = new Web3(ganache.provider())
    // 引入合约的json
    const CourseList = require(path.resolve(__dirname, '../src/compiled/CourseList.json'))
    const Course = require(path.resolve(__dirname, '../src/compiled/Course.json'))
    
    
    // 定义几个全局变量,所有测试都需要
    let accounts
    // 实例
    let courseList
    let course
    
    describe('测试课程的智能', () => {
    
        before(async () => {
            // 测试前的数据初始化
            accounts = await web3.eth.getAccounts()
    
            console.log(accounts)
            // 1. 虚拟部署一个合约
            courseList = await new web3.eth.Contract(JSON.parse(CourseList.interface))
                .deploy({ data: CourseList.bytecode })
                .send({
                    // 最后一个是创建者——重点
                    from: accounts[9],
                    gas: '5000000'
                })
    
        })
    
        it('合约部署成功', () => {
            assert.ok(courseList.options.address)
        })
    
        it('测试添加课程', async () => {
            const oldaddress = await courseList.methods.getCourse().call()
            assert.equal(oldaddress.length, 0)
            await courseList.methods.createCourse(
                '蜗牛的React课程'
            )
                .send({
                    from: accounts[0],
                    gas: '5000000'
                })
            const address = await courseList.methods.getCourse().call()
            assert.equal(address.length, 1)
            console.log(address)
    
        })
    
        it("添加课程的属性", async () => {
            const [address] = await courseList.methods.getCourse().call()
            // 添加的课程合约的地址
            course = await new web3.eth.Contract(JSON.parse(Course.interface), address)
            const name = await course.methods.name().call()
            assert.equal(name, '蜗牛的React课程')
        })
    
    
    
        //删除功能
        it("只能ceo能删", async () => {
            await courseList.methods.createCourse(
                '蜗牛的Vue课程'
            )
                .send({
                    from: accounts[0],
                    gas: '5000000'
                })
            const address = await courseList.methods.getCourse().call()
            assert.equal(address.length, 2)
    
          await courseList.methods.removeCourse(0).send({
            from:accounts[9],
            gas:'5000000'
          })
          const address1 = await courseList.methods.getCourse().call()
          console.log(address1)
          assert.equal(address1.length,1)
          
        })
    
        it('判断是不是ceo',async ()=>{
            const isCeo1 = await courseList.methods.isCeo().call({
              from :accounts[9]
            })
            const isCeo2 = await courseList.methods.isCeo().call({
              from :accounts[1]
            })
            assert.ok(isCeo1)
            assert.ok(!isCeo2)
          })
          
    
    })
    

    6.完善课程的属性,添加其他属性

    6.1 添加一下属性

    课程: owner

    课程创建者 name

    课程名 content

    课程简介 target

    课程目标是募资多少 ETH

    fundingPrice 众筹价格

    price 上线价格

    img 课程头图

    video 视频

    count 多少人支持

    isOnline 是否上线

    6.2 合约里添加Course以及createCourse完善
    //Imooc.sol
    function createCourse(string _name,string _content,uint _target,uint _fundingPrice,uint _price,string _img) public{
        address newCourse = new Course(ceo,msg.sender, _name, _content, _target, 				  	_fundingPrice, _price, _img);
        courses.push(newCourse);
      }
    
    //Imooc.sol
    contract Course{
      address public ceo;
      address public owner;
      string public name;
      string public content;
      uint public target;
      uint public fundingPrice;
      uint public price;
      string public img;
      string public video;
      bool public isOnline;
      uint public count;
      constructor(address _ceo, address _owner,string _name,string _content,uint _target,uint _fundingPrice,uint _price,string _img) public{
        ceo = _ceo;
        owner = _owner;
        name = _name;
        content = _content;
        target = _target;
        fundingPrice = _fundingPrice;
        price = _price;
        img = _img;
        video = '';
        count = 0;
        isOnline = false;
      }
            }
    
    6.3 编写测试逻辑,完善属性
     it('测试添加课程', async () => {
            const oldaddress = await courseList.methods.getCourse().call()
            assert.equal(oldaddress.length, 0)
            await courseList.methods.createCourse(
                '蜗牛的React课程',
                "React+redux+reactrouter4开发招聘app",
                web3.utils.toWei('8'),
                // 众筹价格
                web3.utils.toWei('2'),
                web3.utils.toWei('4'),
                "图片的hash"
            )
                .send({
                    from: accounts[0],
                    gas: '5000000'
                })
            const address = await courseList.methods.getCourse().call()
            assert.equal(address.length, 1)
    
        })
        it("添加课程的属性", async () => {
            const [address] = await courseList.methods.getCourse().call()
            // 添加的课程合约的地址
            course = await new web3.eth.Contract(JSON.parse(Course.interface), address)
            const name = await course.methods.name().call()
            const content = await course.methods.content().call()
            const target = await course.methods.target().call()
            const fundingPrice = await course.methods.fundingPrice().call()
            const price = await course.methods.price().call()
            const img = await course.methods.img().call()
            const count = await course.methods.count().call()
            const isOnline = await course.methods.isOnline().call()
            assert.equal(name, '蜗牛的React课程')
            assert.equal(content, 'React+redux+reactrouter4开发招聘app')
            assert.equal(target, web3.utils.toWei('8'))
            assert.equal(fundingPrice, web3.utils.toWei('2'))
            assert.equal(price, web3.utils.toWei('4'))
            assert.equal(img, "图片的hash")
            assert.ok(!isOnline)
            assert.equal(count, 0)
        })
    
      it("只能ceo能删", async ()=>{
            await courseList.methods.createCourse(
              '蜗牛的Vue课程',
              'vue也是个好框架,简单好上手',
              web3.utils.toWei('8'),
              // 众筹价格
              web3.utils.toWei('2'),
              web3.utils.toWei('4'),
              "图片的hash1"   
              )
                  .send({
                    from:accounts[0],
                    gas:'5000000'
                  })
            const address = await courseList.methods.getCourse().call()
            assert.equal(address.length,2)
        })
    

    7.用户购买课程及课程上线

    7.1 设置用户列表
        // 用户购买信息
      mapping(address=>uint) public users;
    
    7.2 用户购买合约以及课程上线

    课程上线之后众筹的钱立刻全部打给众筹者,之后再有用户购买,则进行分成。给ceo一成的利润。

    // 众筹或者购买
      function buy() public payable{
        // 1. 用户没有购买过
        require(users[msg.sender]==0);
        if(isOnline){
          // 如果上线了 必须得用上线价格购买
          require(price == msg.value);
        }else{
          // 如果上线了 必须得用众筹价格购买
          require(fundingPrice == msg.value);
        }
        users[msg.sender] = msg.value;
        // 统计人数
        count += 1;
        
        if(target <= count*fundingPrice){
            // 钱超出目标
            if(isOnline){
              // 上线之后的购买
              uint value = msg.value;
              // 分成
              ceo.transfer(value/10);
              owner.transfer(value-value/10);
            }else{
              // 没上线 第一次超出
              isOnline = true;
              // 转账
              // 上线之前的钱,都在合约内部,众筹者是拿不到的
              owner.transfer(count*fundingPrice);
    
            }
        }
      }
    
    7.3 用户获取课程详情
    // 获取详情
      function getDetail() public view returns(string,string,uint,uint,uint,string,string,uint,bool,uint){
        uint role;
        if(owner==msg.sender){
          role = 0; //课程创建者
        }else if(users[msg.sender]>0){
          role = 1; // 已购买
        }else{
          role = 2; // 没买
        }
        return (
          name,
          content,
          target,
          fundingPrice,
          price,
          img,
          video,
          count,
          isOnline,
          role
        );
      }
    
    7.4 上线之后众筹者才可以添加视频——ipfs地址
        function addVideo(string _video) public{
        require(msg.sender==owner);
        require(isOnline==true);
        video = _video;
      }
    
    7.5编译通过

    image-20190928123234719

    8.课程购买测试编写

    8.1 金钱转换

    wei

    finney

    szabo

    ether

    1 ether == 10^3 finney
    1 ether == 10^6 szabo
    1 ether == 10^18 Wei
    
    it('金钱转换',()=>{
        assert.equal(web3.utils.toWei('2'),'2000000000000000000')
      })
    
    8.2 课程购买
          it('课程购买',async()=>{
            await course.methods.buy().send({
              from:accounts[2],
              value:web3.utils.toWei('2')
            })
            const value = await course.methods.users(accounts[2]).call()
            const count = await course.methods.count().call()
            assert.equal(value,web3.utils.toWei('2'))
            assert.equal(count,1)
    
            // 输出value及users+
            console.log("钱是:")
            console.log(value)
            // console.log("uers是:")
    
            
            // 用户role的判断
            const detail = await course.methods.getDetail().call({from:accounts[0]})
            assert.equal(detail[9],0)
        
            // 课程
            console.log(detail)
            const detail2 = await course.methods.getDetail().call({from:accounts[2]})
            assert.equal(detail2[9],1)
        
            const detail3 = await course.methods.getDetail().call({from:accounts[5]})
            assert.equal(detail3[9],2)
          })
    

    image-20190928130026973

    8.3 引入bignumber.js

    npm install bignumber.js

    const BigNumber = require('bignumber.js')

    8.4 还没上线的话,钱不入账
          it('还没上线,购买的课不入账',async()=>{
            const oldBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
            await course.methods.buy().send({
              from:accounts[3],
              value:web3.utils.toWei('2')
            })
            const newBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
            const diff = newBlance.minus(oldBlance)
            assert.equal(diff,0)
          })
    
    8.5 还没上线的话,不能上传视频
    it('还没上线,不能上传视频',async()=>{
        
            try{
              await course.methods.addVideo('video的hash')
                        .send({
                          from:accounts[0],
                          gas:'5000000'
                        })
              assert.ok(false)
            }catch(e){
                console.log(e)
              assert.equal(e.name,'o')
            }
          })
    
    
    
    8.6 不能重复购买
      it('不能重复购买',async()=>{
        try{
          await course.methods.buy().send({
            from:accounts[2],
            value:web3.utils.toWei('2')
          })
          assert.ok(false)
    
        }catch(e){
          console.log(e.name)
          assert.equal(e.name,'RuntimeError')
    
        }
    
      })
    
    8.7 课程必须是众筹价格
      it('课程必须是众筹价格',async()=>{
        try{
          await course.methods.buy().send({
            from:accounts[4],
            value:web3.utils.toWei('3')
          })
          assert.ok(false)
    
        }catch(e){
          assert.equal(e.name,'RuntimeError')
    
        }
    
      })
    
    8.8 众筹上线后,钱到账
      
      it('众筹上线后,钱到账',async()=>{
        const oldBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
    
        // 8 众筹家是2  买4次就上线
        await course.methods.buy().send({
          from:accounts[4],
          value:web3.utils.toWei('2')
        })
        await course.methods.buy().send({
          from:accounts[5],
          value:web3.utils.toWei('2')
        })
        const count = await course.methods.count().call()
        const isOnline = await course.methods.isOnline().call()
        assert.equal(count,4)
        assert.ok(isOnline)
        const newBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
        const diff = newBlance.minus(oldBlance)
        assert.equal(diff,web3.utils.toWei('8'))
      })
    
    8.9 课程必须是线上的价格
       it('课程必须是线上的价格',async()=>{
        try{
          await course.methods.buy().send({
            from:accounts[6],
            value:web3.utils.toWei('2')
          })
          assert.ok(false)
    
        }catch(e){
          assert.equal(e.name,'RuntimeError')
        }
    
      })
    
     it('课程必须是线上的价格2',async()=>{
        // try{
          await course.methods.buy().send({
            from:accounts[6],
            value:web3.utils.toWei('4')
          })
          const count = await course.methods.count().call()
          assert.equal(count,5)
    
        // }catch(e){
        //   assert.equal(e.name,'RuntimeError')
        // }
      })
    
    
    8.10 上线之后购买 有分成收益
      it('上线之后购买 有分成收益',async()=>{
        // try{
          // ceo的约
        const oldCeoBlance = new BigNumber(await web3.eth.getBalance(accounts[9]))
        // 课程创建者
        const oldOwnerBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
    
          await course.methods.buy().send({
            from:accounts[7],
            value:web3.utils.toWei('4')
          })
          const newCeoBlance = new BigNumber(await web3.eth.getBalance(accounts[9]))
          const newOwnerBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
    
          const diffCeo = newCeoBlance.minus(oldCeoBlance)
          const diffOwner = newOwnerBlance.minus(oldOwnerBlance)
          assert.equal(diffCeo, web3.utils.toWei('0.4'))
          assert.equal(diffOwner, web3.utils.toWei('3.6'))
        // }catch(e){
        //   assert.equal(e.name,'RuntimeError')
        // }
      })
    
    8.11 上线之后,可以上传视频
    it('上线之后,可以上传视频',async()=>{
        
          await course.methods.addVideo('video的hash')
                    .send({
                      from:accounts[0],
                      gas:'5000000'
                    })
          const video = await  course.methods.video().call()
          assert.equal(video,'video的hash')
      })
    
    8.12 完整测试代码
    const path = require('path');
    const assert = require('assert');
    const Web3 = require('web3')
    const ganache = require('ganache-cli')
    const BigNumber = require('bignumber.js')
    const web3 = new Web3(ganache.provider())
    // 引入合约的json
    const CourseList = require(path.resolve(__dirname, '../src/compiled/CourseList.json'))
    const Course = require(path.resolve(__dirname, '../src/compiled/Course.json'))
    
    
    // 定义几个全局变量,所有测试都需要
    let accounts
    // 实例
    let courseList
    let course
    
    describe('测试课程的智能', () => {
    
        before(async () => {
            // 测试前的数据初始化
            accounts = await web3.eth.getAccounts()
    
            console.log(accounts)
            // 1. 虚拟部署一个合约
            courseList = await new web3.eth.Contract(JSON.parse(CourseList.interface))
                .deploy({ data: CourseList.bytecode })
                .send({
                    // 最后一个是创建者——重点
                    from: accounts[9],
                    gas: '5000000'
                })
    
        })
    
        it('合约部署成功', () => {
            assert.ok(courseList.options.address)
        })
    
        // it('测试添加课程', async () => {
        //     const oldaddress = await courseList.methods.getCourse().call()
        //     assert.equal(oldaddress.length, 0)
        //     await courseList.methods.createCourse(
        //         '蜗牛的React课程'
        //     )
        //         .send({
        //             from: accounts[0],
        //             gas: '5000000'
        //         })
        //     const address = await courseList.methods.getCourse().call()
        //     assert.equal(address.length, 1)
        //     console.log(address)
    
        // })
    
        // it("添加课程的属性", async () => {
        //     const [address] = await courseList.methods.getCourse().call()
        //     // 添加的课程合约的地址
        //     course = await new web3.eth.Contract(JSON.parse(Course.interface), address)
        //     const name = await course.methods.name().call()
        //     assert.equal(name, '蜗牛的React课程')
        // })
        it('测试添加课程', async () => {
            const oldaddress = await courseList.methods.getCourse().call()
            assert.equal(oldaddress.length, 0)
            await courseList.methods.createCourse(
                '蜗牛的React课程',
                "React+redux+reactrouter4开发招聘app",
                web3.utils.toWei('8'),
                // 众筹价格
                web3.utils.toWei('2'),
                web3.utils.toWei('4'),
                "图片的hash"
            )
                .send({
                    from: accounts[0],
                    gas: '5000000'
                })
            const address = await courseList.methods.getCourse().call()
            assert.equal(address.length, 1)
    
        })
        it("添加课程的属性", async () => {
            const [address] = await courseList.methods.getCourse().call()
            // 添加的课程合约的地址
            course = await new web3.eth.Contract(JSON.parse(Course.interface), address)
            const name = await course.methods.name().call()
            const content = await course.methods.content().call()
            const target = await course.methods.target().call()
            const fundingPrice = await course.methods.fundingPrice().call()
            const price = await course.methods.price().call()
            const img = await course.methods.img().call()
            const count = await course.methods.count().call()
            const isOnline = await course.methods.isOnline().call()
            assert.equal(name, '蜗牛的React课程')
            assert.equal(content, 'React+redux+reactrouter4开发招聘app')
            assert.equal(target, web3.utils.toWei('8'))
            assert.equal(fundingPrice, web3.utils.toWei('2'))
            assert.equal(price, web3.utils.toWei('4'))
            assert.equal(img, "图片的hash")
            assert.ok(!isOnline)
            assert.equal(count, 0)
        })
    
    
        //删除功能
        // it("只能ceo能删", async () => {
        //     await courseList.methods.createCourse(
        //         '蜗牛的Vue课程'
        //     )
        //         .send({
        //             from: accounts[0],
        //             gas: '5000000'
        //         })
        //     const address = await courseList.methods.getCourse().call()
        //     assert.equal(address.length, 2)
    
        //     await courseList.methods.removeCourse(0).send({
        //         from: accounts[9],
        //         gas: '5000000'
        //     })
        //     const address1 = await courseList.methods.getCourse().call()
        //     console.log(address1)
        //     assert.equal(address1.length, 1)
    
        // })
        it("只能ceo能删", async ()=>{
            await courseList.methods.createCourse(
              '蜗牛的Vue课程',
              'vue也是个好框架,简单好上手',
              web3.utils.toWei('8'),
              // 众筹价格
              web3.utils.toWei('2'),
              web3.utils.toWei('4'),
              "图片的hash1"   
              )
                  .send({
                    from:accounts[0],
                    gas:'5000000'
                  })
            const address = await courseList.methods.getCourse().call()
            assert.equal(address.length,2)
        })
    
        it('判断是不是ceo', async () => {
            const isCeo1 = await courseList.methods.isCeo().call({
                from: accounts[9]
            })
            const isCeo2 = await courseList.methods.isCeo().call({
                from: accounts[1]
            })
            assert.ok(isCeo1)
            assert.ok(!isCeo2)
        })
    
        it('金钱转换',()=>{
            assert.equal(web3.utils.toWei('2'),'2000000000000000000')
          })
    
          it('课程购买',async()=>{
            await course.methods.buy().send({
              from:accounts[2],
              value:web3.utils.toWei('2')
            })
            const value = await course.methods.users(accounts[2]).call()
            const count = await course.methods.count().call()
            assert.equal(value,web3.utils.toWei('2'))
            assert.equal(count,1)
    
            // 输出value及users+
            console.log("钱是:")
            console.log(value)
            // console.log("uers是:")
    
            
            // 用户role的判断
            const detail = await course.methods.getDetail().call({from:accounts[0]})
            assert.equal(detail[9],0)
        
            // 课程
            console.log(detail)
            const detail2 = await course.methods.getDetail().call({from:accounts[2]})
            assert.equal(detail2[9],1)
        
            const detail3 = await course.methods.getDetail().call({from:accounts[5]})
            assert.equal(detail3[9],2)
          })
    
          it('还没上线,购买的课不入账',async()=>{
            const oldBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
            await course.methods.buy().send({
              from:accounts[3],
              value:web3.utils.toWei('2')
            })
            const newBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
            const diff = newBlance.minus(oldBlance)
            assert.equal(diff,0)
          })
    
          it('还没上线,不能上传视频',async()=>{
        
            try{
              await course.methods.addVideo('video的hash')
                        .send({
                          from:accounts[0],
                          gas:'5000000'
                        })
              assert.ok(false)
            }catch(e){
                console.log(e)
              assert.equal(e.name,'o')
            }
          })
          it('不能重复购买',async()=>{
            try{
              await course.methods.buy().send({
                from:accounts[2],
                value:web3.utils.toWei('2')
              })
              assert.ok(false)
        
            }catch(e){
              console.log(e.name)
              assert.equal(e.name,'RuntimeError')
        
            }
        
          })
          it('课程必须是众筹价格',async()=>{
            try{
              await course.methods.buy().send({
                from:accounts[4],
                value:web3.utils.toWei('3')
              })
              assert.ok(false)
        
            }catch(e){
              assert.equal(e.name,'RuntimeError')
        
            }
        
          })
          
          it('众筹上线后,钱到账',async()=>{
            const oldBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
        
            // 8 众筹家是2  买4次就上线
            await course.methods.buy().send({
              from:accounts[4],
              value:web3.utils.toWei('2')
            })
            await course.methods.buy().send({
              from:accounts[5],
              value:web3.utils.toWei('2')
            })
            const count = await course.methods.count().call()
            const isOnline = await course.methods.isOnline().call()
            assert.equal(count,4)
            assert.ok(isOnline)
            const newBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
            const diff = newBlance.minus(oldBlance)
            assert.equal(diff,web3.utils.toWei('8'))
          })
          it('课程必须是线上的价格',async()=>{
            try{
              await course.methods.buy().send({
                from:accounts[6],
                value:web3.utils.toWei('2')
              })
              assert.ok(false)
        
            }catch(e){
              assert.equal(e.name,'RuntimeError')
            }
        
          })
          it('课程必须是线上的价格2',async()=>{
            // try{
              await course.methods.buy().send({
                from:accounts[6],
                value:web3.utils.toWei('4')
              })
              const count = await course.methods.count().call()
              assert.equal(count,5)
        
            // }catch(e){
            //   assert.equal(e.name,'RuntimeError')
            // }
          })
          it('上线之后购买 有分成收益',async()=>{
            // try{
              // ceo的约
            const oldCeoBlance = new BigNumber(await web3.eth.getBalance(accounts[9]))
            // 课程创建者
            const oldOwnerBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
        
              await course.methods.buy().send({
                from:accounts[7],
                value:web3.utils.toWei('4')
              })
              const newCeoBlance = new BigNumber(await web3.eth.getBalance(accounts[9]))
              const newOwnerBlance = new BigNumber(await web3.eth.getBalance(accounts[0]))
        
              const diffCeo = newCeoBlance.minus(oldCeoBlance)
              const diffOwner = newOwnerBlance.minus(oldOwnerBlance)
              assert.equal(diffCeo, web3.utils.toWei('0.4'))
              assert.equal(diffOwner, web3.utils.toWei('3.6'))
            // }catch(e){
            //   assert.equal(e.name,'RuntimeError')
            // }
          })
        
          it('上线之后,可以上传视频',async()=>{
            
              await course.methods.addVideo('video的hash')
                        .send({
                          from:accounts[0],
                          gas:'5000000'
                        })
              const video = await  course.methods.video().call()
              assert.equal(video,'video的hash')
          })
    
    })
    

    END

  • 相关阅读:
    【JavaScript】实现队列Queue
    【Leetcode刷题篇】1.两数之和(JS)
    【48个原生JS网页小demo】1.信息切换
    【JavaScript】原生实现call bind apply
    【JavaScript】Interview(精简版)
    【JavaScript】4种常见的内存泄露
    【JavaScript】原型和原型链
    论自作音乐播放器涉及知识点总结
    Android横竖屏切换继续播放视频
    Android上传头像代码,相机,相册,裁剪
  • 原文地址:https://www.cnblogs.com/oneapple/p/13288040.html
Copyright © 2020-2023  润新知